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