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