source: rtems-libbsd/freebsd/lib/libc/nameser/ns_name.c @ 165dd8e

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 165dd8e was 165dd8e, checked in by Sebastian Huber <sebastian.huber@…>, on 04/08/15 at 13:37:49

Update to FreeBSD Stable/9 2015-04-08

  • Property mode set to 100644
File size: 24.7 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
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
21static 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 <rtems/bsd/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
53static const char       digits[] = "0123456789";
54
55static 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
76static int              special(int);
77static int              printable(int);
78static int              dn_find(const u_char *, const u_char *,
79                                const u_char * const *,
80                                const u_char * const *);
81static int              encode_bitsring(const char **, const char *,
82                                        unsigned char **, unsigned char **,
83                                        unsigned const char *);
84static int              labellen(const u_char *);
85static 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 */
100int
101ns_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 */
204int
205ns_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 */
221int
222ns_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
357int
358ns_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 */
407int
408ns_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 */
422int
423ns_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 */
518int
519ns_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) {
601cleanup:
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 */
619int
620ns_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 */
648int
649ns_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 */
663void
664ns_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 */
682int
683ns_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 */
724ssize_t
725ns_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 */
746int
747ns_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 */
770int
771ns_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 */
793int
794ns_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 */
843int
844ns_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 */
873static int
874special(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 */
898static int
899printable(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 */
907static int
908mklower(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 */
924static int
925dn_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
982static int
983decode_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
1030static int
1031encode_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
1136static int
1137labellen(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 */
Note: See TracBrowser for help on using the repository browser.