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