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