backout 29799f914cab, Bug 917642 - [Helix] Please update the helix blobs
[gecko.git] / other-licenses / android / ns_name.c
blob889bf3c339e06efe9710ab63e8cb662215e33663
1 /* $NetBSD: ns_name.c,v 1.3 2004/11/07 02:19:49 christos Exp $ */
3 /*
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1996,1999 by Internet Software Consortium.
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.
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.
21 * This version of this file is derived from Android 2.3 "Gingerbread",
22 * which contains uncredited changes by Android/Google developers. It has
23 * been modified in 2011 for use in the Android build of Mozilla Firefox by
24 * Mozilla contributors (including Michael Edwards <m.k.edwards@gmail.com>,
25 * and Steve Workman <sjhworkman@gmail.com>).
26 * These changes are offered under the same license as the original NetBSD
27 * file, whose copyright and license are unchanged above.
30 #define ANDROID_CHANGES 1
31 #define MOZILLA_NECKO_EXCLUDE_CODE 1
33 #include <sys/cdefs.h>
34 #ifndef lint
35 #ifdef notdef
36 static const char rcsid[] = "Id: ns_name.c,v 1.3.2.4.4.2 2004/05/04 03:27:47 marka Exp";
37 #else
38 __RCSID("$NetBSD: ns_name.c,v 1.3 2004/11/07 02:19:49 christos Exp $");
39 #endif
40 #endif
42 #include <sys/types.h>
44 #include <netinet/in.h>
45 #include "arpa_nameser.h"
47 #include <errno.h>
48 #ifdef ANDROID_CHANGES
49 #include "resolv_private.h"
50 #else
51 #include <resolv.h>
52 #endif
53 #include <string.h>
54 #include <ctype.h>
55 #include <stdlib.h>
56 #include <limits.h>
58 #ifdef SPRINTF_CHAR
59 # define SPRINTF(x) strlen(sprintf/**/x)
60 #else
61 # define SPRINTF(x) ((size_t)sprintf x)
62 #endif
64 #define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */
65 #define DNS_LABELTYPE_BITSTRING 0x41
67 /* Data. */
69 static const char digits[] = "0123456789";
71 static const char digitvalue[256] = {
72 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
73 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
74 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
75 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
76 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
77 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
78 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
79 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
80 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
81 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
82 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
83 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
84 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
85 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
86 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
87 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
90 /* Forward. */
92 static int special(int);
93 static int printable(int);
94 static int dn_find(const u_char *, const u_char *,
95 const u_char * const *,
96 const u_char * const *);
97 static int encode_bitsring(const char **, const char *,
98 unsigned char **, unsigned char **,
99 unsigned const char *);
100 static int labellen(const u_char *);
101 static int decode_bitstring(const unsigned char **,
102 char *, const char *);
104 /* Public. */
107 * ns_name_ntop(src, dst, dstsiz)
108 * Convert an encoded domain name to printable ascii as per RFC1035.
109 * return:
110 * Number of bytes written to buffer, or -1 (with errno set)
111 * notes:
112 * The root is returned as "."
113 * All other domains are returned in non absolute form
116 ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
118 const u_char *cp;
119 char *dn, *eom;
120 u_char c;
121 u_int n;
122 int l;
124 cp = src;
125 dn = dst;
126 eom = dst + dstsiz;
128 while ((n = *cp++) != 0) {
129 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
130 /* Some kind of compression pointer. */
131 errno = EMSGSIZE;
132 return (-1);
134 if (dn != dst) {
135 if (dn >= eom) {
136 errno = EMSGSIZE;
137 return (-1);
139 *dn++ = '.';
141 if ((l = labellen(cp - 1)) < 0) {
142 errno = EMSGSIZE; /* XXX */
143 return(-1);
145 if (dn + l >= eom) {
146 errno = EMSGSIZE;
147 return (-1);
149 if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
150 int m;
152 if (n != DNS_LABELTYPE_BITSTRING) {
153 /* XXX: labellen should reject this case */
154 errno = EINVAL;
155 return(-1);
157 if ((m = decode_bitstring(&cp, dn, eom)) < 0)
159 errno = EMSGSIZE;
160 return(-1);
162 dn += m;
163 continue;
165 for (; l > 0; l--) {
166 c = *cp++;
167 if (special(c)) {
168 if (dn + 1 >= eom) {
169 errno = EMSGSIZE;
170 return (-1);
172 *dn++ = '\\';
173 *dn++ = (char)c;
174 } else if (!printable(c)) {
175 if (dn + 3 >= eom) {
176 errno = EMSGSIZE;
177 return (-1);
179 *dn++ = '\\';
180 *dn++ = digits[c / 100];
181 *dn++ = digits[(c % 100) / 10];
182 *dn++ = digits[c % 10];
183 } else {
184 if (dn >= eom) {
185 errno = EMSGSIZE;
186 return (-1);
188 *dn++ = (char)c;
192 if (dn == dst) {
193 if (dn >= eom) {
194 errno = EMSGSIZE;
195 return (-1);
197 *dn++ = '.';
199 if (dn >= eom) {
200 errno = EMSGSIZE;
201 return (-1);
203 *dn++ = '\0';
204 return (dn - dst);
208 * ns_name_pton(src, dst, dstsiz)
209 * Convert a ascii string into an encoded domain name as per RFC1035.
210 * return:
211 * -1 if it fails
212 * 1 if string was fully qualified
213 * 0 is string was not fully qualified
214 * notes:
215 * Enforces label and domain length limits.
219 ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
221 u_char *label, *bp, *eom;
222 int c, n, escaped, e = 0;
223 char *cp;
225 escaped = 0;
226 bp = dst;
227 eom = dst + dstsiz;
228 label = bp++;
230 while ((c = *src++) != 0) {
231 if (escaped) {
232 if (c == '[') { /* start a bit string label */
233 if ((cp = strchr(src, ']')) == NULL) {
234 errno = EINVAL; /* ??? */
235 return(-1);
237 if ((e = encode_bitsring(&src, cp + 2,
238 &label, &bp, eom))
239 != 0) {
240 errno = e;
241 return(-1);
243 escaped = 0;
244 label = bp++;
245 if ((c = *src++) == 0)
246 goto done;
247 else if (c != '.') {
248 errno = EINVAL;
249 return(-1);
251 continue;
253 else if ((cp = strchr(digits, c)) != NULL) {
254 n = (cp - digits) * 100;
255 if ((c = *src++) == 0 ||
256 (cp = strchr(digits, c)) == NULL) {
257 errno = EMSGSIZE;
258 return (-1);
260 n += (cp - digits) * 10;
261 if ((c = *src++) == 0 ||
262 (cp = strchr(digits, c)) == NULL) {
263 errno = EMSGSIZE;
264 return (-1);
266 n += (cp - digits);
267 if (n > 255) {
268 errno = EMSGSIZE;
269 return (-1);
271 c = n;
273 escaped = 0;
274 } else if (c == '\\') {
275 escaped = 1;
276 continue;
277 } else if (c == '.') {
278 c = (bp - label - 1);
279 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
280 errno = EMSGSIZE;
281 return (-1);
283 if (label >= eom) {
284 errno = EMSGSIZE;
285 return (-1);
287 *label = c;
288 /* Fully qualified ? */
289 if (*src == '\0') {
290 if (c != 0) {
291 if (bp >= eom) {
292 errno = EMSGSIZE;
293 return (-1);
295 *bp++ = '\0';
297 if ((bp - dst) > MAXCDNAME) {
298 errno = EMSGSIZE;
299 return (-1);
301 return (1);
303 if (c == 0 || *src == '.') {
304 errno = EMSGSIZE;
305 return (-1);
307 label = bp++;
308 continue;
310 if (bp >= eom) {
311 errno = EMSGSIZE;
312 return (-1);
314 *bp++ = (u_char)c;
316 c = (bp - label - 1);
317 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
318 errno = EMSGSIZE;
319 return (-1);
321 done:
322 if (label >= eom) {
323 errno = EMSGSIZE;
324 return (-1);
326 *label = c;
327 if (c != 0) {
328 if (bp >= eom) {
329 errno = EMSGSIZE;
330 return (-1);
332 *bp++ = 0;
334 if ((bp - dst) > MAXCDNAME) { /* src too big */
335 errno = EMSGSIZE;
336 return (-1);
338 return (0);
341 #ifndef MOZILLA_NECKO_EXCLUDE_CODE
343 * ns_name_ntol(src, dst, dstsiz)
344 * Convert a network strings labels into all lowercase.
345 * return:
346 * Number of bytes written to buffer, or -1 (with errno set)
347 * notes:
348 * Enforces label and domain length limits.
352 ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
354 const u_char *cp;
355 u_char *dn, *eom;
356 u_char c;
357 u_int n;
358 int l;
360 cp = src;
361 dn = dst;
362 eom = dst + dstsiz;
364 if (dn >= eom) {
365 errno = EMSGSIZE;
366 return (-1);
368 while ((n = *cp++) != 0) {
369 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
370 /* Some kind of compression pointer. */
371 errno = EMSGSIZE;
372 return (-1);
374 *dn++ = n;
375 if ((l = labellen(cp - 1)) < 0) {
376 errno = EMSGSIZE;
377 return (-1);
379 if (dn + l >= eom) {
380 errno = EMSGSIZE;
381 return (-1);
383 for (; l > 0; l--) {
384 c = *cp++;
385 if (isupper(c))
386 *dn++ = tolower(c);
387 else
388 *dn++ = c;
391 *dn++ = '\0';
392 return (dn - dst);
394 #endif
397 * ns_name_unpack(msg, eom, src, dst, dstsiz)
398 * Unpack a domain name from a message, source may be compressed.
399 * return:
400 * -1 if it fails, or consumed octets if it succeeds.
403 ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
404 u_char *dst, size_t dstsiz)
406 const u_char *srcp, *dstlim;
407 u_char *dstp;
408 int n, len, checked, l;
410 len = -1;
411 checked = 0;
412 dstp = dst;
413 srcp = src;
414 dstlim = dst + dstsiz;
415 if (srcp < msg || srcp >= eom) {
416 errno = EMSGSIZE;
417 return (-1);
419 /* Fetch next label in domain name. */
420 while ((n = *srcp++) != 0) {
421 /* Check for indirection. */
422 switch (n & NS_CMPRSFLGS) {
423 case 0:
424 case NS_TYPE_ELT:
425 /* Limit checks. */
426 if ((l = labellen(srcp - 1)) < 0) {
427 errno = EMSGSIZE;
428 return(-1);
430 if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
431 errno = EMSGSIZE;
432 return (-1);
434 checked += l + 1;
435 *dstp++ = n;
436 memcpy(dstp, srcp, (size_t)l);
437 dstp += l;
438 srcp += l;
439 break;
441 case NS_CMPRSFLGS:
442 if (srcp >= eom) {
443 errno = EMSGSIZE;
444 return (-1);
446 if (len < 0)
447 len = srcp - src + 1;
448 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
449 if (srcp < msg || srcp >= eom) { /* Out of range. */
450 errno = EMSGSIZE;
451 return (-1);
453 checked += 2;
455 * Check for loops in the compressed name;
456 * if we've looked at the whole message,
457 * there must be a loop.
459 if (checked >= eom - msg) {
460 errno = EMSGSIZE;
461 return (-1);
463 break;
465 default:
466 errno = EMSGSIZE;
467 return (-1); /* flag error */
470 *dstp = '\0';
471 if (len < 0)
472 len = srcp - src;
473 return (len);
477 * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
478 * Pack domain name 'domain' into 'comp_dn'.
479 * return:
480 * Size of the compressed name, or -1.
481 * notes:
482 * 'dnptrs' is an array of pointers to previous compressed names.
483 * dnptrs[0] is a pointer to the beginning of the message. The array
484 * ends with NULL.
485 * 'lastdnptr' is a pointer to the end of the array pointed to
486 * by 'dnptrs'.
487 * Side effects:
488 * The list of pointers in dnptrs is updated for labels inserted into
489 * the message as we compress the name. If 'dnptr' is NULL, we don't
490 * try to compress names. If 'lastdnptr' is NULL, we don't update the
491 * list.
494 ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
495 const u_char **dnptrs, const u_char **lastdnptr)
497 u_char *dstp;
498 const u_char **cpp, **lpp, *eob, *msg;
499 const u_char *srcp;
500 int n, l, first = 1;
502 srcp = src;
503 dstp = dst;
504 eob = dstp + dstsiz;
505 lpp = cpp = NULL;
506 if (dnptrs != NULL) {
507 if ((msg = *dnptrs++) != NULL) {
508 for (cpp = dnptrs; *cpp != NULL; cpp++)
510 lpp = cpp; /* end of list to search */
512 } else
513 msg = NULL;
515 /* make sure the domain we are about to add is legal */
516 l = 0;
517 do {
518 int l0;
520 n = *srcp;
521 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
522 errno = EMSGSIZE;
523 return (-1);
525 if ((l0 = labellen(srcp)) < 0) {
526 errno = EINVAL;
527 return(-1);
529 l += l0 + 1;
530 if (l > MAXCDNAME) {
531 errno = EMSGSIZE;
532 return (-1);
534 srcp += l0 + 1;
535 } while (n != 0);
537 /* from here on we need to reset compression pointer array on error */
538 srcp = src;
539 do {
540 /* Look to see if we can use pointers. */
541 n = *srcp;
542 if (n != 0 && msg != NULL) {
543 l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
544 (const u_char * const *)lpp);
545 if (l >= 0) {
546 if (dstp + 1 >= eob) {
547 goto cleanup;
549 *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
550 *dstp++ = l % 256;
551 return (dstp - dst);
553 /* Not found, save it. */
554 if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
555 (dstp - msg) < 0x4000 && first) {
556 *cpp++ = dstp;
557 *cpp = NULL;
558 first = 0;
561 /* copy label to buffer */
562 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
563 /* Should not happen. */
564 goto cleanup;
566 n = labellen(srcp);
567 if (dstp + 1 + n >= eob) {
568 goto cleanup;
570 memcpy(dstp, srcp, (size_t)(n + 1));
571 srcp += n + 1;
572 dstp += n + 1;
573 } while (n != 0);
575 if (dstp > eob) {
576 cleanup:
577 if (msg != NULL)
578 *lpp = NULL;
579 errno = EMSGSIZE;
580 return (-1);
582 return (dstp - dst);
586 * ns_name_uncompress(msg, eom, src, dst, dstsiz)
587 * Expand compressed domain name to presentation format.
588 * return:
589 * Number of bytes read out of `src', or -1 (with errno set).
590 * note:
591 * Root domain returns as "." not "".
594 ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
595 char *dst, size_t dstsiz)
597 u_char tmp[NS_MAXCDNAME];
598 int n;
600 if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
601 return (-1);
602 if (ns_name_ntop(tmp, dst, dstsiz) == -1)
603 return (-1);
604 return (n);
608 * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
609 * Compress a domain name into wire format, using compression pointers.
610 * return:
611 * Number of bytes consumed in `dst' or -1 (with errno set).
612 * notes:
613 * 'dnptrs' is an array of pointers to previous compressed names.
614 * dnptrs[0] is a pointer to the beginning of the message.
615 * The list ends with NULL. 'lastdnptr' is a pointer to the end of the
616 * array pointed to by 'dnptrs'. Side effect is to update the list of
617 * pointers for labels inserted into the message as we compress the name.
618 * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
619 * is NULL, we don't update the list.
622 ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
623 const u_char **dnptrs, const u_char **lastdnptr)
625 u_char tmp[NS_MAXCDNAME];
627 if (ns_name_pton(src, tmp, sizeof tmp) == -1)
628 return (-1);
629 return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr));
632 #ifndef MOZILLA_NECKO_EXCLUDE_CODE
634 * Reset dnptrs so that there are no active references to pointers at or
635 * after src.
637 void
638 ns_name_rollback(const u_char *src, const u_char **dnptrs,
639 const u_char **lastdnptr)
641 while (dnptrs < lastdnptr && *dnptrs != NULL) {
642 if (*dnptrs >= src) {
643 *dnptrs = NULL;
644 break;
646 dnptrs++;
649 #endif
652 * ns_name_skip(ptrptr, eom)
653 * Advance *ptrptr to skip over the compressed name it points at.
654 * return:
655 * 0 on success, -1 (with errno set) on failure.
658 ns_name_skip(const u_char **ptrptr, const u_char *eom)
660 const u_char *cp;
661 u_int n;
662 int l;
664 cp = *ptrptr;
665 while (cp < eom && (n = *cp++) != 0) {
666 /* Check for indirection. */
667 switch (n & NS_CMPRSFLGS) {
668 case 0: /* normal case, n == len */
669 cp += n;
670 continue;
671 case NS_TYPE_ELT: /* EDNS0 extended label */
672 if ((l = labellen(cp - 1)) < 0) {
673 errno = EMSGSIZE; /* XXX */
674 return(-1);
676 cp += l;
677 continue;
678 case NS_CMPRSFLGS: /* indirection */
679 cp++;
680 break;
681 default: /* illegal type */
682 errno = EMSGSIZE;
683 return (-1);
685 break;
687 if (cp > eom) {
688 errno = EMSGSIZE;
689 return (-1);
691 *ptrptr = cp;
692 return (0);
695 /* Private. */
698 * special(ch)
699 * Thinking in noninternationalized USASCII (per the DNS spec),
700 * is this characted special ("in need of quoting") ?
701 * return:
702 * boolean.
704 static int
705 special(int ch) {
706 switch (ch) {
707 case 0x22: /* '"' */
708 case 0x2E: /* '.' */
709 case 0x3B: /* ';' */
710 case 0x5C: /* '\\' */
711 case 0x28: /* '(' */
712 case 0x29: /* ')' */
713 /* Special modifiers in zone files. */
714 case 0x40: /* '@' */
715 case 0x24: /* '$' */
716 return (1);
717 default:
718 return (0);
723 * printable(ch)
724 * Thinking in noninternationalized USASCII (per the DNS spec),
725 * is this character visible and not a space when printed ?
726 * return:
727 * boolean.
729 static int
730 printable(int ch) {
731 return (ch > 0x20 && ch < 0x7f);
735 * Thinking in noninternationalized USASCII (per the DNS spec),
736 * convert this character to lower case if it's upper case.
738 static int
739 mklower(int ch) {
740 if (ch >= 0x41 && ch <= 0x5A)
741 return (ch + 0x20);
742 return (ch);
746 * dn_find(domain, msg, dnptrs, lastdnptr)
747 * Search for the counted-label name in an array of compressed names.
748 * return:
749 * offset from msg if found, or -1.
750 * notes:
751 * dnptrs is the pointer to the first name on the list,
752 * not the pointer to the start of the message.
754 static int
755 dn_find(const u_char *domain, const u_char *msg,
756 const u_char * const *dnptrs,
757 const u_char * const *lastdnptr)
759 const u_char *dn, *cp, *sp;
760 const u_char * const *cpp;
761 u_int n;
763 for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
764 sp = *cpp;
766 * terminate search on:
767 * root label
768 * compression pointer
769 * unusable offset
771 while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
772 (sp - msg) < 0x4000) {
773 dn = domain;
774 cp = sp;
775 while ((n = *cp++) != 0) {
777 * check for indirection
779 switch (n & NS_CMPRSFLGS) {
780 case 0: /* normal case, n == len */
781 n = labellen(cp - 1); /* XXX */
783 if (n != *dn++)
784 goto next;
786 for (; n > 0; n--)
787 if (mklower(*dn++) !=
788 mklower(*cp++))
789 goto next;
790 /* Is next root for both ? */
791 if (*dn == '\0' && *cp == '\0')
792 return (sp - msg);
793 if (*dn)
794 continue;
795 goto next;
796 case NS_CMPRSFLGS: /* indirection */
797 cp = msg + (((n & 0x3f) << 8) | *cp);
798 break;
800 default: /* illegal type */
801 errno = EMSGSIZE;
802 return (-1);
805 next: ;
806 sp += *sp + 1;
809 errno = ENOENT;
810 return (-1);
813 static int
814 decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
816 const unsigned char *cp = *cpp;
817 char *beg = dn, tc;
818 int b, blen, plen, i;
820 if ((blen = (*cp & 0xff)) == 0)
821 blen = 256;
822 plen = (blen + 3) / 4;
823 plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
824 if (dn + plen >= eom)
825 return(-1);
827 cp++;
828 i = SPRINTF((dn, "\\[x"));
829 if (i < 0)
830 return (-1);
831 dn += i;
832 for (b = blen; b > 7; b -= 8, cp++) {
833 i = SPRINTF((dn, "%02x", *cp & 0xff));
834 if (i < 0)
835 return (-1);
836 dn += i;
838 if (b > 4) {
839 tc = *cp++;
840 i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
841 if (i < 0)
842 return (-1);
843 dn += i;
844 } else if (b > 0) {
845 tc = *cp++;
846 i = SPRINTF((dn, "%1x",
847 (((u_int32_t)tc >> 4) & 0x0f) & (0x0f << (4 - b))));
848 if (i < 0)
849 return (-1);
850 dn += i;
852 i = SPRINTF((dn, "/%d]", blen));
853 if (i < 0)
854 return (-1);
855 dn += i;
857 *cpp = cp;
858 return(dn - beg);
861 static int
862 encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
863 unsigned char ** dst, unsigned const char *eom)
865 int afterslash = 0;
866 const char *cp = *bp;
867 unsigned char *tp;
868 char c;
869 const char *beg_blen;
870 char *end_blen = NULL;
871 int value = 0, count = 0, tbcount = 0, blen = 0;
873 beg_blen = end_blen = NULL;
875 /* a bitstring must contain at least 2 characters */
876 if (end - cp < 2)
877 return(EINVAL);
879 /* XXX: currently, only hex strings are supported */
880 if (*cp++ != 'x')
881 return(EINVAL);
882 if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */
883 return(EINVAL);
885 for (tp = *dst + 1; cp < end && tp < eom; cp++) {
886 switch((c = *cp)) {
887 case ']': /* end of the bitstring */
888 if (afterslash) {
889 if (beg_blen == NULL)
890 return(EINVAL);
891 blen = (int)strtol(beg_blen, &end_blen, 10);
892 if (*end_blen != ']')
893 return(EINVAL);
895 if (count)
896 *tp++ = ((value << 4) & 0xff);
897 cp++; /* skip ']' */
898 goto done;
899 case '/':
900 afterslash = 1;
901 break;
902 default:
903 if (afterslash) {
904 if (!isdigit(c&0xff))
905 return(EINVAL);
906 if (beg_blen == NULL) {
908 if (c == '0') {
909 /* blen never begings with 0 */
910 return(EINVAL);
912 beg_blen = cp;
914 } else {
915 if (!isxdigit(c&0xff))
916 return(EINVAL);
917 value <<= 4;
918 value += digitvalue[(int)c];
919 count += 4;
920 tbcount += 4;
921 if (tbcount > 256)
922 return(EINVAL);
923 if (count == 8) {
924 *tp++ = value;
925 count = 0;
928 break;
931 done:
932 if (cp >= end || tp >= eom)
933 return(EMSGSIZE);
936 * bit length validation:
937 * If a <length> is present, the number of digits in the <bit-data>
938 * MUST be just sufficient to contain the number of bits specified
939 * by the <length>. If there are insignificant bits in a final
940 * hexadecimal or octal digit, they MUST be zero.
941 * RFC 2673, Section 3.2.
943 if (blen > 0) {
944 int traillen;
946 if (((blen + 3) & ~3) != tbcount)
947 return(EINVAL);
948 traillen = tbcount - blen; /* between 0 and 3 */
949 if (((value << (8 - traillen)) & 0xff) != 0)
950 return(EINVAL);
952 else
953 blen = tbcount;
954 if (blen == 256)
955 blen = 0;
957 /* encode the type and the significant bit fields */
958 **labelp = DNS_LABELTYPE_BITSTRING;
959 **dst = blen;
961 *bp = cp;
962 *dst = tp;
964 return(0);
967 static int
968 labellen(const u_char *lp)
970 int bitlen;
971 u_char l = *lp;
973 if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
974 /* should be avoided by the caller */
975 return(-1);
978 if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
979 if (l == DNS_LABELTYPE_BITSTRING) {
980 if ((bitlen = *(lp + 1)) == 0)
981 bitlen = 256;
982 return((bitlen + 7 ) / 8 + 1);
984 return(-1); /* unknwon ELT */
986 return(l);