(getanswer_r): Correctly track usage of user-provided buffer.
[kopensolaris-gnu/glibc.git] / resolv / res_comp.c
1 /*
2  * ++Copyright++ 1985, 1993
3  * -
4  * Copyright (c) 1985, 1993
5  *    The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 4. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  * -
31  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32  *
33  * Permission to use, copy, modify, and distribute this software for any
34  * purpose with or without fee is hereby granted, provided that the above
35  * copyright notice and this permission notice appear in all copies, and that
36  * the name of Digital Equipment Corporation not be used in advertising or
37  * publicity pertaining to distribution of the document or software without
38  * specific, written prior permission.
39  *
40  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47  * SOFTWARE.
48  * -
49  * --Copyright--
50  */
51
52 #if defined(LIBC_SCCS) && !defined(lint)
53 static char sccsid[] = "@(#)res_comp.c  8.1 (Berkeley) 6/4/93";
54 static char rcsid[] = "$Id$";
55 #endif /* LIBC_SCCS and not lint */
56
57 #include <sys/types.h>
58 #include <sys/param.h>
59 #include <netinet/in.h>
60 #include <arpa/nameser.h>
61
62 #include <ctype.h>
63 #include <errno.h>
64 #include <resolv.h>
65 #include <stdio.h>
66
67 #if defined(BSD) && (BSD >= 199103)
68 # include <unistd.h>
69 # include <string.h>
70 #else
71 # include "../conf/portability.h"
72 #endif
73
74 extern int      __ns_name_ntop __P((const u_char *, char *, size_t));
75 static int      ns_name_pton __P((const char *, u_char *, size_t));
76 extern int      __ns_name_unpack __P((const u_char *, const u_char *,
77                                       const u_char *, u_char *, size_t));
78 static int      ns_name_pack __P((const u_char *, u_char *, int,
79                                   const u_char **, const u_char **));
80 static int      ns_name_uncompress __P((const u_char *, const u_char *,
81                                         const u_char *, char *, size_t));
82 static int      ns_name_compress __P((const char *, u_char *, size_t,
83                                       const u_char **, const u_char **));
84 static int      ns_name_skip __P((const u_char **, const u_char *));
85
86 /*
87  * Expand compressed domain name 'comp_dn' to full domain name.
88  * 'msg' is a pointer to the begining of the message,
89  * 'eomorig' points to the first location after the message,
90  * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
91  * Return size of compressed name or -1 if there was an error.
92  */
93 int
94 dn_expand(msg, eom, src, dst, dstsiz)
95         const u_char *msg;
96         const u_char *eom;
97         const u_char *src;
98         char *dst;
99         int dstsiz;
100 {
101         int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
102
103         if (n > 0 && dst[0] == '.')
104                 dst[0] = '\0';
105         return (n);
106 }
107
108 /*
109  * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
110  * Return the size of the compressed name or -1.
111  * 'length' is the size of the array pointed to by 'comp_dn'.
112  */
113 int
114 dn_comp(src, dst, dstsiz, dnptrs, lastdnptr)
115         const char *src;
116         u_char *dst;
117         int dstsiz;
118         u_char **dnptrs;
119         u_char **lastdnptr;
120 {
121         return (ns_name_compress(src, dst, (size_t)dstsiz,
122                                  (const u_char **)dnptrs,
123                                  (const u_char **)lastdnptr));
124 }
125
126 /*
127  * Skip over a compressed domain name. Return the size or -1.
128  */
129 int
130 __dn_skipname(ptr, eom)
131         const u_char *ptr;
132         const u_char *eom;
133 {
134         const u_char *saveptr = ptr;
135
136         if (ns_name_skip(&ptr, eom) == -1)
137                 return (-1);
138         return (ptr - saveptr);
139 }
140
141 /*
142  * Verify that a domain name uses an acceptable character set.
143  */
144
145 /*
146  * Note the conspicuous absence of ctype macros in these definitions.  On
147  * non-ASCII hosts, we can't depend on string literals or ctype macros to
148  * tell us anything about network-format data.  The rest of the BIND system
149  * is not careful about this, but for some reason, we're doing it right here.
150  */
151 #define PERIOD 0x2e
152 #define hyphenchar(c) ((c) == 0x2d)
153 #define underscorechar(c) ((c) == 0x5f)
154 #define bslashchar(c) ((c) == 0x5c)
155 #define periodchar(c) ((c) == PERIOD)
156 #define asterchar(c) ((c) == 0x2a)
157 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
158                    || ((c) >= 0x61 && (c) <= 0x7a))
159 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
160
161 #define borderchar(c) (alphachar(c) || digitchar(c))
162 #define middlechar(c) (borderchar(c) || hyphenchar(c) || underscorechar(c))
163 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
164
165 int
166 res_hnok(dn)
167         const char *dn;
168 {
169         int ppch = '\0', pch = PERIOD, ch = *dn++;
170
171         while (ch != '\0') {
172                 int nch = *dn++;
173
174                 if (periodchar(ch)) {
175                         /* NULL */;
176                 } else if (periodchar(pch)) {
177                         if (!borderchar(ch))
178                                 return (0);
179                 } else if (periodchar(nch) || nch == '\0') {
180                         if (!borderchar(ch))
181                                 return (0);
182                 } else {
183                         if (!middlechar(ch))
184                                 return (0);
185                 }
186                 ppch = pch, pch = ch, ch = nch;
187         }
188         return (1);
189 }
190
191 /*
192  * hostname-like (A, MX, WKS) owners can have "*" as their first label
193  * but must otherwise be as a host name.
194  */
195 int
196 res_ownok(dn)
197         const char *dn;
198 {
199         if (asterchar(dn[0])) {
200                 if (periodchar(dn[1]))
201                         return (res_hnok(dn+2));
202                 if (dn[1] == '\0')
203                         return (1);
204         }
205         return (res_hnok(dn));
206 }
207
208 /*
209  * SOA RNAMEs and RP RNAMEs can have any printable character in their first
210  * label, but the rest of the name has to look like a host name.
211  */
212 int
213 res_mailok(dn)
214         const char *dn;
215 {
216         int ch, escaped = 0;
217
218         /* "." is a valid missing representation */
219         if (*dn == '\0')
220                 return(1);
221
222         /* otherwise <label>.<hostname> */
223         while ((ch = *dn++) != '\0') {
224                 if (!domainchar(ch))
225                         return (0);
226                 if (!escaped && periodchar(ch))
227                         break;
228                 if (escaped)
229                         escaped = 0;
230                 else if (bslashchar(ch))
231                         escaped = 1;
232         }
233         if (periodchar(ch))
234                 return (res_hnok(dn));
235         return(0);
236 }
237
238 /*
239  * This function is quite liberal, since RFC 1034's character sets are only
240  * recommendations.
241  */
242 int
243 res_dnok(dn)
244         const char *dn;
245 {
246         int ch;
247
248         while ((ch = *dn++) != '\0')
249                 if (!domainchar(ch))
250                         return (0);
251         return (1);
252 }
253
254 /*
255  * Routines to insert/extract short/long's.
256  */
257
258 u_int16_t
259 _getshort(msgp)
260         register const u_char *msgp;
261 {
262         register u_int16_t u;
263
264         GETSHORT(u, msgp);
265         return (u);
266 }
267
268 #ifdef NeXT
269 /*
270  * nExt machines have some funky library conventions, which we must maintain.
271  */
272 u_int16_t
273 res_getshort(msgp)
274         register const u_char *msgp;
275 {
276         return (_getshort(msgp));
277 }
278 #endif
279
280 u_int32_t
281 _getlong(msgp)
282         register const u_char *msgp;
283 {
284         register u_int32_t u;
285
286         GETLONG(u, msgp);
287         return (u);
288 }
289
290 void
291 #if defined(__STDC__) || defined(__cplusplus)
292 __putshort(register u_int16_t s, register u_char *msgp) /* must match proto */
293 #else
294 __putshort(s, msgp)
295         register u_int16_t s;
296         register u_char *msgp;
297 #endif
298 {
299         PUTSHORT(s, msgp);
300 }
301
302 void
303 __putlong(l, msgp)
304         register u_int32_t l;
305         register u_char *msgp;
306 {
307         PUTLONG(l, msgp);
308 }
309
310 /* ++ From BIND 8.1.1. ++ */
311 /*
312  * Copyright (c) 1996 by Internet Software Consortium.
313  *
314  * Permission to use, copy, modify, and distribute this software for any
315  * purpose with or without fee is hereby granted, provided that the above
316  * copyright notice and this permission notice appear in all copies.
317  *
318  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
319  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
320  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
321  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
322  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
323  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
324  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
325  * SOFTWARE.
326  */
327
328 /*"Id: ns_name.c,v 1.1 1997/12/13 02:41:13 vixie Exp vixie"*/
329
330 /*#include "port_before.h"*/
331
332 /*#include <sys/types.h>*/
333
334 /*#include <netinet/in.h>*/
335 /*#include <arpa/nameser.h>*/
336
337 /*#include <errno.h>*/
338 /*#include <resolv.h>*/
339 /*#include <string.h>*/
340
341 /*#include "port_after.h"*/
342
343 #define NS_CMPRSFLGS    0xc0    /* Flag bits indicating name compression. */
344 #define NS_MAXCDNAME    255     /* maximum compressed domain name */
345
346 /* Data. */
347
348 static const char       digits[] = "0123456789";
349
350 /* Forward. */
351
352 static int              special(int);
353 static int              printable(int);
354 static int              dn_find(const u_char *, const u_char *,
355                                 const u_char * const *,
356                                 const u_char * const *);
357
358 /* Public. */
359
360 /*
361  * ns_name_ntop(src, dst, dstsiz)
362  *      Convert an encoded domain name to printable ascii as per RFC1035.
363  * return:
364  *      Number of bytes written to buffer, or -1 (with errno set)
365  * notes:
366  *      The root is returned as "."
367  *      All other domains are returned in non absolute form
368  */
369 int
370 __ns_name_ntop(src, dst, dstsiz)
371         const u_char *src;
372         char *dst;
373         size_t dstsiz;
374 {
375         const u_char *cp;
376         char *dn, *eom;
377         u_char c;
378         u_int n;
379
380         cp = src;
381         dn = dst;
382         eom = dst + dstsiz;
383
384         while ((n = *cp++) != 0) {
385                 if ((n & NS_CMPRSFLGS) != 0) {
386                         /* Some kind of compression pointer. */
387                         __set_errno (EINVAL);
388                         return (-1);
389                 }
390                 if (dn != dst) {
391                         if (dn >= eom) {
392                                 __set_errno (EMSGSIZE);
393                                 return (-1);
394                         }
395                         *dn++ = '.';
396                 }
397                 if (dn + n >= eom) {
398                         __set_errno (EMSGSIZE);
399                         return (-1);
400                 }
401                 for ((void)NULL; n > 0; n--) {
402                         c = *cp++;
403                         if (special(c)) {
404                                 if (dn + 1 >= eom) {
405                                         __set_errno (EMSGSIZE);
406                                         return (-1);
407                                 }
408                                 *dn++ = '\\';
409                                 *dn++ = (char)c;
410                         } else if (!printable(c)) {
411                                 if (dn + 3 >= eom) {
412                                         __set_errno (EMSGSIZE);
413                                         return (-1);
414                                 }
415                                 *dn++ = '\\';
416                                 *dn++ = digits[c / 100];
417                                 *dn++ = digits[(c % 100) / 10];
418                                 *dn++ = digits[c % 10];
419                         } else {
420                                 if (dn >= eom) {
421                                         __set_errno (EMSGSIZE);
422                                         return (-1);
423                                 }
424                                 *dn++ = (char)c;
425                         }
426                 }
427         }
428         if (dn == dst) {
429                 if (dn >= eom) {
430                         __set_errno (EMSGSIZE);
431                         return (-1);
432                 }
433                 *dn++ = '.';
434         }
435         if (dn >= eom) {
436                 __set_errno (EMSGSIZE);
437                 return (-1);
438         }
439         *dn++ = '\0';
440         return (dn - dst);
441 }
442
443 /*
444  * ns_name_pton(src, dst, dstsiz)
445  *      Convert a ascii string into an encoded domain name as per RFC1035.
446  * return:
447  *      -1 if it fails
448  *      1 if string was fully qualified
449  *      0 is string was not fully qualified
450  * notes:
451  *      Enforces label and domain length limits.
452  */
453
454 static int
455 ns_name_pton(src, dst, dstsiz)
456         const char *src;
457         u_char *dst;
458         size_t dstsiz;
459 {
460         u_char *label, *bp, *eom;
461         int c, n, escaped;
462         char *cp;
463
464         escaped = 0;
465         bp = dst;
466         eom = dst + dstsiz;
467         label = bp++;
468
469         while ((c = *src++) != 0) {
470                 if (escaped) {
471                         if ((cp = strchr(digits, c)) != NULL) {
472                                 n = (cp - digits) * 100;
473                                 if ((c = *src++) == 0 ||
474                                     (cp = strchr(digits, c)) == NULL) {
475                                         __set_errno (EMSGSIZE);
476                                         return (-1);
477                                 }
478                                 n += (cp - digits) * 10;
479                                 if ((c = *src++) == 0 ||
480                                     (cp = strchr(digits, c)) == NULL) {
481                                         __set_errno (EMSGSIZE);
482                                         return (-1);
483                                 }
484                                 n += (cp - digits);
485                                 if (n > 255) {
486                                         __set_errno (EMSGSIZE);
487                                         return (-1);
488                                 }
489                                 c = n;
490                         }
491                         escaped = 0;
492                 } else if (c == '\\') {
493                         escaped = 1;
494                         continue;
495                 } else if (c == '.') {
496                         c = (bp - label - 1);
497                         if ((c & NS_CMPRSFLGS) != 0) {  /* Label too big. */
498                                 __set_errno (EMSGSIZE);
499                                 return (-1);
500                         }
501                         if (label >= eom) {
502                                 __set_errno (EMSGSIZE);
503                                 return (-1);
504                         }
505                         *label = c;
506                         /* Fully qualified ? */
507                         if (*src == '\0') {
508                                 if (c != 0) {
509                                         if (bp >= eom) {
510                                                 __set_errno (EMSGSIZE);
511                                                 return (-1);
512                                         }
513                                         *bp++ = '\0';
514                                 }
515                                 if ((bp - dst) > MAXCDNAME) {
516                                         __set_errno (EMSGSIZE);
517                                         return (-1);
518                                 }
519                                 return (1);
520                         }
521                         if (c == 0) {
522                                 __set_errno (EMSGSIZE);
523                                 return (-1);
524                         }
525                         label = bp++;
526                         continue;
527                 }
528                 if (bp >= eom) {
529                         __set_errno (EMSGSIZE);
530                         return (-1);
531                 }
532                 *bp++ = (u_char)c;
533         }
534         c = (bp - label - 1);
535         if ((c & NS_CMPRSFLGS) != 0) {          /* Label too big. */
536                 __set_errno (EMSGSIZE);
537                 return (-1);
538         }
539         if (label >= eom) {
540                 __set_errno (EMSGSIZE);
541                 return (-1);
542         }
543         *label = c;
544         if (c != 0) {
545                 if (bp >= eom) {
546                         __set_errno (EMSGSIZE);
547                         return (-1);
548                 }
549                 *bp++ = 0;
550         }
551         if ((bp - dst) > MAXCDNAME) {   /* src too big */
552                 __set_errno (EMSGSIZE);
553                 return (-1);
554         }
555         return (0);
556 }
557
558 /*
559  * ns_name_unpack(msg, eom, src, dst, dstsiz)
560  *      Unpack a domain name from a message, source may be compressed.
561  * return:
562  *      -1 if it fails, or consumed octets if it succeeds.
563  */
564 int
565 __ns_name_unpack(msg, eom, src, dst, dstsiz)
566         const u_char *msg;
567         const u_char *eom;
568         const u_char *src;
569         u_char *dst;
570         size_t dstsiz;
571 {
572         const u_char *srcp, *dstlim;
573         u_char *dstp;
574 #ifdef _LIBC
575         /* We don't want warnings!  */
576         int n, len, checked;
577 #else
578         int n, c, len, checked;
579 #endif
580
581         len = -1;
582         checked = 0;
583         dstp = dst;
584         srcp = src;
585         dstlim = dst + dstsiz;
586         if (srcp < msg || srcp >= eom) {
587                 __set_errno (EMSGSIZE);
588                 return (-1);
589         }
590         /* Fetch next label in domain name. */
591         while ((n = *srcp++) != 0) {
592                 /* Check for indirection. */
593                 switch (n & NS_CMPRSFLGS) {
594                 case 0:
595                         /* Limit checks. */
596                         if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
597                                 __set_errno (EMSGSIZE);
598                                 return (-1);
599                         }
600                         checked += n + 1;
601                         *dstp++ = n;
602                         memcpy(dstp, srcp, n);
603                         dstp += n;
604                         srcp += n;
605                         break;
606
607                 case NS_CMPRSFLGS:
608                         if (srcp >= eom) {
609                                 __set_errno (EMSGSIZE);
610                                 return (-1);
611                         }
612                         if (len < 0)
613                                 len = srcp - src + 1;
614                         srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
615                         if (srcp < msg || srcp >= eom) {  /* Out of range. */
616                                 __set_errno (EMSGSIZE);
617                                 return (-1);
618                         }
619                         checked += 2;
620                         /*
621                          * Check for loops in the compressed name;
622                          * if we've looked at the whole message,
623                          * there must be a loop.
624                          */
625                         if (checked >= eom - msg) {
626                                 __set_errno (EMSGSIZE);
627                                 return (-1);
628                         }
629                         break;
630
631                 default:
632                         __set_errno (EMSGSIZE);
633                         return (-1);                    /* flag error */
634                 }
635         }
636         *dstp = '\0';
637         if (len < 0)
638                 len = srcp - src;
639         return (len);
640 }
641
642 /*
643  * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
644  *      Pack domain name 'domain' into 'comp_dn'.
645  * return:
646  *      Size of the compressed name, or -1.
647  * notes:
648  *      'dnptrs' is an array of pointers to previous compressed names.
649  *      dnptrs[0] is a pointer to the beginning of the message. The array
650  *      ends with NULL.
651  *      'lastdnptr' is a pointer to the end of the array pointed to
652  *      by 'dnptrs'.
653  * Side effects:
654  *      The list of pointers in dnptrs is updated for labels inserted into
655  *      the message as we compress the name.  If 'dnptr' is NULL, we don't
656  *      try to compress names. If 'lastdnptr' is NULL, we don't update the
657  *      list.
658  */
659 static int
660 ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
661         const u_char *src;
662         u_char *dst;
663         int dstsiz;
664         const u_char **dnptrs;
665         const u_char **lastdnptr;
666 {
667         u_char *dstp;
668         const u_char **cpp, **lpp, *eob, *msg;
669         const u_char *srcp;
670         int n, l;
671
672         srcp = src;
673         dstp = dst;
674         eob = dstp + dstsiz;
675         lpp = cpp = NULL;
676         if (dnptrs != NULL) {
677                 if ((msg = *dnptrs++) != NULL) {
678                         for (cpp = dnptrs; *cpp != NULL; cpp++)
679                                 (void)NULL;
680                         lpp = cpp;      /* end of list to search */
681                 }
682         } else
683                 msg = NULL;
684
685         /* make sure the domain we are about to add is legal */
686         l = 0;
687         do {
688                 n = *srcp;
689                 if ((n & NS_CMPRSFLGS) != 0) {
690                         __set_errno (EMSGSIZE);
691                         return (-1);
692                 }
693                 l += n + 1;
694                 if (l > MAXCDNAME) {
695                         __set_errno (EMSGSIZE);
696                         return (-1);
697                 }
698                 srcp += n + 1;
699         } while (n != 0);
700
701         srcp = src;
702         do {
703                 /* Look to see if we can use pointers. */
704                 n = *srcp;
705                 if (n != 0 && msg != NULL) {
706                         l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
707                                     (const u_char * const *)lpp);
708                         if (l >= 0) {
709                                 if (dstp + 1 >= eob) {
710                                         __set_errno (EMSGSIZE);
711                                         return (-1);
712                                 }
713                                 *dstp++ = (l >> 8) | NS_CMPRSFLGS;
714                                 *dstp++ = l % 256;
715                                 return (dstp - dst);
716                         }
717                         /* Not found, save it. */
718                         if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
719                             (dstp - msg) < 0x4000) {
720                                 *cpp++ = dstp;
721                                 *cpp = NULL;
722                         }
723                 }
724                 /* copy label to buffer */
725                 if (n & NS_CMPRSFLGS) {         /* Should not happen. */
726                         __set_errno (EMSGSIZE);
727                         return (-1);
728                 }
729                 if (dstp + 1 + n >= eob) {
730                         __set_errno (EMSGSIZE);
731                         return (-1);
732                 }
733                 memcpy(dstp, srcp, n + 1);
734                 srcp += n + 1;
735                 dstp += n + 1;
736         } while (n != 0);
737
738         if (dstp > eob) {
739                 if (msg != NULL)
740                         *lpp = NULL;
741                 __set_errno (EMSGSIZE);
742                 return (-1);
743         }
744         return (dstp - dst);
745 }
746
747 /*
748  * ns_name_uncompress(msg, eom, src, dst, dstsiz)
749  *      Expand compressed domain name to presentation format.
750  * return:
751  *      Number of bytes read out of `src', or -1 (with errno set).
752  * note:
753  *      Root domain returns as "." not "".
754  */
755 static int
756 ns_name_uncompress(msg, eom, src, dst, dstsiz)
757         const u_char *msg;
758         const u_char *eom;
759         const u_char *src;
760         char *dst;
761         size_t dstsiz;
762 {
763         u_char tmp[NS_MAXCDNAME];
764         int n;
765
766         if ((n = __ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
767                 return (-1);
768         if (__ns_name_ntop(tmp, dst, dstsiz) == -1)
769                 return (-1);
770         return (n);
771 }
772
773 /*
774  * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
775  *      Compress a domain name into wire format, using compression pointers.
776  * return:
777  *      Number of bytes consumed in `dst' or -1 (with errno set).
778  * notes:
779  *      'dnptrs' is an array of pointers to previous compressed names.
780  *      dnptrs[0] is a pointer to the beginning of the message.
781  *      The list ends with NULL.  'lastdnptr' is a pointer to the end of the
782  *      array pointed to by 'dnptrs'. Side effect is to update the list of
783  *      pointers for labels inserted into the message as we compress the name.
784  *      If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
785  *      is NULL, we don't update the list.
786  */
787 static int
788 ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
789         const char *src;
790         u_char *dst;
791         size_t dstsiz;
792         const u_char **dnptrs;
793         const u_char **lastdnptr;
794 {
795         u_char tmp[NS_MAXCDNAME];
796
797         if (ns_name_pton(src, tmp, sizeof tmp) == -1)
798                 return (-1);
799         return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
800 }
801
802 /*
803  * ns_name_skip(ptrptr, eom)
804  *      Advance *ptrptr to skip over the compressed name it points at.
805  * return:
806  *      0 on success, -1 (with errno set) on failure.
807  */
808 static int
809 ns_name_skip(ptrptr, eom)
810         const u_char **ptrptr;
811         const u_char *eom;
812 {
813         const u_char *cp;
814         u_int n;
815
816         cp = *ptrptr;
817         while (cp < eom && (n = *cp++) != 0) {
818                 /* Check for indirection. */
819                 switch (n & NS_CMPRSFLGS) {
820                 case 0:                 /* normal case, n == len */
821                         cp += n;
822                         continue;
823                 case NS_CMPRSFLGS:      /* indirection */
824                         cp++;
825                         break;
826                 default:                /* illegal type */
827                         __set_errno (EMSGSIZE);
828                         return (-1);
829                 }
830                 break;
831         }
832         if (cp > eom) {
833                 __set_errno (EMSGSIZE);
834                 return (-1);
835         }
836         *ptrptr = cp;
837         return (0);
838 }
839
840 /* Private. */
841
842 /*
843  * special(ch)
844  *      Thinking in noninternationalized USASCII (per the DNS spec),
845  *      is this characted special ("in need of quoting") ?
846  * return:
847  *      boolean.
848  */
849 static int
850 special(ch)
851         int ch;
852 {
853         switch (ch) {
854         case 0x22: /* '"' */
855         case 0x2E: /* '.' */
856         case 0x3B: /* ';' */
857         case 0x5C: /* '\\' */
858         /* Special modifiers in zone files. */
859         case 0x40: /* '@' */
860         case 0x24: /* '$' */
861                 return (1);
862         default:
863                 return (0);
864         }
865 }
866
867 /*
868  * printable(ch)
869  *      Thinking in noninternationalized USASCII (per the DNS spec),
870  *      is this character visible and not a space when printed ?
871  * return:
872  *      boolean.
873  */
874 static int
875 printable(ch)
876         int ch;
877 {
878         return (ch > 0x20 && ch < 0x7f);
879 }
880
881 /*
882  *      Thinking in noninternationalized USASCII (per the DNS spec),
883  *      convert this character to lower case if it's upper case.
884  */
885 static int
886 mklower(ch)
887         int ch;
888 {
889         if (ch >= 0x41 && ch <= 0x5A)
890                 return (ch + 0x20);
891         return (ch);
892 }
893
894 /*
895  * dn_find(domain, msg, dnptrs, lastdnptr)
896  *      Search for the counted-label name in an array of compressed names.
897  * return:
898  *      offset from msg if found, or -1.
899  * notes:
900  *      dnptrs is the pointer to the first name on the list,
901  *      not the pointer to the start of the message.
902  */
903 static int
904 dn_find(domain, msg, dnptrs, lastdnptr)
905         const u_char *domain;
906         const u_char *msg;
907         const u_char * const *dnptrs;
908         const u_char * const *lastdnptr;
909 {
910         const u_char *dn, *cp, *sp;
911         const u_char * const *cpp;
912         u_int n;
913
914         for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
915                 dn = domain;
916                 sp = cp = *cpp;
917                 while ((n = *cp++) != 0) {
918                         /*
919                          * check for indirection
920                          */
921                         switch (n & NS_CMPRSFLGS) {
922                         case 0:                 /* normal case, n == len */
923                                 if (n != *dn++)
924                                         goto next;
925                                 for ((void)NULL; n > 0; n--)
926                                         if (mklower(*dn++) != mklower(*cp++))
927                                                 goto next;
928                                 /* Is next root for both ? */
929                                 if (*dn == '\0' && *cp == '\0')
930                                         return (sp - msg);
931                                 if (*dn)
932                                         continue;
933                                 goto next;
934
935                         case NS_CMPRSFLGS:      /* indirection */
936                                 cp = msg + (((n & 0x3f) << 8) | *cp);
937                                 break;
938
939                         default:        /* illegal type */
940                                 __set_errno (EMSGSIZE);
941                                 return (-1);
942                         }
943                 }
944  next: ;
945         }
946         __set_errno (ENOENT);
947         return (-1);
948 }
949
950 /* -- From BIND 8.1.1. -- */