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