]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - resolv/res_comp.c
resolv: Move ns_name_ntop to its own file and into libc
[thirdparty/glibc.git] / resolv / res_comp.c
index aa6afa39ebed71cf59153ed8ab96dac8ea79e2c3..c53788643ab644f1277b8d0f1290b0b43230cce8 100644 (file)
@@ -1,9 +1,25 @@
+/* Domain name processing functions.
+   Copyright (C) 1995-2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
 /*
- * ++Copyright++ 1985, 1993
- * -
  * Copyright (c) 1985, 1993
  *    The Regents of the University of California.  All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- * -
+ */
+
+/*
  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- * 
+ *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies, and that
  * the name of Digital Equipment Corporation not be used in advertising or
  * publicity pertaining to distribution of the document or software without
  * specific, written prior permission.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  * SOFTWARE.
- * -
- * --Copyright--
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
-static char rcsid[] = "$Id$";
-#endif /* LIBC_SCCS and not lint */
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
 
+#include <sys/types.h>
 #include <sys/param.h>
 #include <netinet/in.h>
 #include <arpa/nameser.h>
-
-#include <stdio.h>
-#include <resolv.h>
 #include <ctype.h>
-
-#if defined(BSD) && (BSD >= 199103)
-# include <unistd.h>
-# include <string.h>
-#else
-# include "../conf/portability.h"
-#endif
-
-static int     dn_find __P((u_char *exp_dn, u_char *msg,
-                            u_char **dnptrs, u_char **lastdnptr));
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
 
 /*
  * Expand compressed domain name 'comp_dn' to full domain name.
- * 'msg' is a pointer to the begining of the message,
+ * 'msg' is a pointer to the beginning of the message,
  * 'eomorig' points to the first location after the message,
  * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
  * Return size of compressed name or -1 if there was an error.
  */
 int
-dn_expand(msg, eomorig, comp_dn, exp_dn, length)
-       const u_char *msg, *eomorig, *comp_dn;
-       char *exp_dn;
-       int length;
+dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
+         char *dst, int dstsiz)
 {
-       register const u_char *cp;
-       register char *dn;
-       register int n, c;
-       char *eom;
-       int len = -1, checked = 0;
+       int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
 
-       dn = exp_dn;
-       cp = comp_dn;
-       eom = exp_dn + length;
-       /*
-        * fetch next label in domain name
-        */
-       while (n = *cp++) {
-               /*
-                * Check for indirection
-                */
-               switch (n & INDIR_MASK) {
-               case 0:
-                       if (dn != exp_dn) {
-                               if (dn >= eom)
-                                       return (-1);
-                               *dn++ = '.';
-                       }
-                       if (dn+n >= eom)
-                               return (-1);
-                       checked += n + 1;
-                       while (--n >= 0) {
-                               if ((c = *cp++) == '.') {
-                                       if (dn + n + 2 >= eom)
-                                               return (-1);
-                                       *dn++ = '\\';
-                               }
-                               *dn++ = c;
-                               if (cp >= eomorig)      /* out of range */
-                                       return (-1);
-                       }
-                       break;
-
-               case INDIR_MASK:
-                       if (len < 0)
-                               len = cp - comp_dn + 1;
-                       cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
-                       if (cp < msg || cp >= eomorig)  /* out of range */
-                               return (-1);
-                       checked += 2;
-                       /*
-                        * Check for loops in the compressed name;
-                        * if we've looked at the whole message,
-                        * there must be a loop.
-                        */
-                       if (checked >= eomorig - msg)
-                               return (-1);
-                       break;
-
-               default:
-                       return (-1);                    /* flag error */
-               }
-       }
-       *dn = '\0';
-       for (dn = exp_dn; (c = *dn) != '\0'; dn++)
-               if (isascii(c) && isspace(c))
-                       return (-1);
-       if (len < 0)
-               len = cp - comp_dn;
-       return (len);
+       if (n > 0 && dst[0] == '.')
+               dst[0] = '\0';
+       return (n);
 }
+libresolv_hidden_def (dn_expand)
 
 /*
- * Compress domain name 'exp_dn' into 'comp_dn'.
+ * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
  * Return the size of the compressed name or -1.
  * 'length' is the size of the array pointed to by 'comp_dn'.
- * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
- * is a pointer to the beginning of the message. The list ends with NULL.
- * 'lastdnptr' is a pointer to the end of the arrary pointed to
- * by 'dnptrs'. Side effect is to update the list of pointers for
- * labels inserted into the message as we compress the name.
- * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
- * is NULL, we don't update the list.
  */
 int
-dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
-       const char *exp_dn;
-       u_char *comp_dn, **dnptrs, **lastdnptr;
-       int length;
+dn_comp(const char *src, u_char *dst, int dstsiz,
+       u_char **dnptrs, u_char **lastdnptr)
 {
-       register u_char *cp, *dn;
-       register int c, l;
-       u_char **cpp, **lpp, *sp, *eob;
-       u_char *msg;
-
-       dn = (u_char *)exp_dn;
-       cp = comp_dn;
-       eob = cp + length;
-       lpp = cpp = NULL;
-       if (dnptrs != NULL) {
-               if ((msg = *dnptrs++) != NULL) {
-                       for (cpp = dnptrs; *cpp != NULL; cpp++)
-                               ;
-                       lpp = cpp;      /* end of list to search */
-               }
-       } else
-               msg = NULL;
-       for (c = *dn++; c != '\0'; ) {
-               /* look to see if we can use pointers */
-               if (msg != NULL) {
-                       if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
-                               if (cp+1 >= eob)
-                                       return (-1);
-                               *cp++ = (l >> 8) | INDIR_MASK;
-                               *cp++ = l % 256;
-                               return (cp - comp_dn);
-                       }
-                       /* not found, save it */
-                       if (lastdnptr != NULL && cpp < lastdnptr-1) {
-                               *cpp++ = cp;
-                               *cpp = NULL;
-                       }
-               }
-               sp = cp++;      /* save ptr to length byte */
-               do {
-                       if (c == '.') {
-                               c = *dn++;
-                               break;
-                       }
-                       if (c == '\\') {
-                               if ((c = *dn++) == '\0')
-                                       break;
-                       }
-                       if (cp >= eob) {
-                               if (msg != NULL)
-                                       *lpp = NULL;
-                               return (-1);
-                       }
-                       *cp++ = c;
-               } while ((c = *dn++) != '\0');
-               /* catch trailing '.'s but not '..' */
-               if ((l = cp - sp - 1) == 0 && c == '\0') {
-                       cp--;
-                       break;
-               }
-               if (l <= 0 || l > MAXLABEL) {
-                       if (msg != NULL)
-                               *lpp = NULL;
-                       return (-1);
-               }
-               *sp = l;
-       }
-       if (cp >= eob) {
-               if (msg != NULL)
-                       *lpp = NULL;
-               return (-1);
-       }
-       *cp++ = '\0';
-       return (cp - comp_dn);
+       return (ns_name_compress(src, dst, (size_t)dstsiz,
+                                (const u_char **)dnptrs,
+                                (const u_char **)lastdnptr));
 }
+libresolv_hidden_def (dn_comp)
 
 /*
  * Skip over a compressed domain name. Return the size or -1.
  */
 int
-__dn_skipname(comp_dn, eom)
-       const u_char *comp_dn, *eom;
-{
-       register const u_char *cp;
-       register int n;
+dn_skipname(const u_char *ptr, const u_char *eom) {
+       const u_char *saveptr = ptr;
 
-       cp = comp_dn;
-       while (cp < eom && (n = *cp++)) {
-               /*
-                * check for indirection
-                */
-               switch (n & INDIR_MASK) {
-               case 0:                 /* normal case, n == len */
-                       cp += n;
-                       continue;
-               case INDIR_MASK:        /* indirection */
-                       cp++;
-                       break;
-               default:                /* illegal type */
-                       return (-1);
-               }
-               break;
-       }
-       if (cp > eom)
+       if (ns_name_skip(&ptr, eom) == -1)
                return (-1);
-       return (cp - comp_dn);
+       return (ptr - saveptr);
 }
+libresolv_hidden_def (dn_skipname)
 
-static int
-mklower(ch)
-       register int ch;
+/* Return true if the string consists of printable ASCII characters
+   only.  */
+static bool
+printable_string (const char *dn)
 {
-       if (isascii(ch) && isupper(ch))
-               return (tolower(ch));
-       return (ch);
+  while (true)
+    {
+      char ch = *dn;
+      if (ch == '\0')
+       return true;
+      if (ch <= ' ' || ch > '~')
+       return false;
+      ++dn;
+    }
 }
 
-/*
- * Search for expanded name from a list of previously compressed names.
- * Return the offset from msg if found or -1.
- * dnptrs is the pointer to the first name on the list,
- * not the pointer to the start of the message.
- */
-static int
-dn_find(exp_dn, msg, dnptrs, lastdnptr)
-       u_char *exp_dn, *msg;
-       u_char **dnptrs, **lastdnptr;
+/* Return true if DN points to a name consisting only of [0-9a-zA-Z_-]
+   characters.  DN must be in DNS wire format, without
+   compression.  */
+static bool
+binary_hnok (const unsigned char *dn)
 {
-       register u_char *dn, *cp, **cpp;
-       register int n;
-       u_char *sp;
-
-       for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
-               dn = exp_dn;
-               sp = cp = *cpp;
-               while (n = *cp++) {
-                       /*
-                        * check for indirection
-                        */
-                       switch (n & INDIR_MASK) {
-                       case 0:         /* normal case, n == len */
-                               while (--n >= 0) {
-                                       if (*dn == '.')
-                                               goto next;
-                                       if (*dn == '\\')
-                                               dn++;
-                                       if (mklower(*dn++) != mklower(*cp++))
-                                               goto next;
-                               }
-                               if ((n = *dn++) == '\0' && *cp == '\0')
-                                       return (sp - msg);
-                               if (n == '.')
-                                       continue;
-                               goto next;
-
-                       case INDIR_MASK:        /* indirection */
-                               cp = msg + (((n & 0x3f) << 8) | *cp);
-                               break;
-
-                       default:        /* illegal type */
-                               return (-1);
-                       }
-               }
-               if (*dn == '\0')
-                       return (sp - msg);
-       next:   ;
+  while (true)
+    {
+      size_t label_length = *dn;
+      if (label_length == 0)
+       break;
+      ++dn;
+      const unsigned char *label_end = dn + label_length;
+      do
+       {
+         unsigned char ch = *dn;
+         if (!(('0' <= ch && ch <= '9')
+               || ('A' <= ch && ch <= 'Z')
+               || ('a' <= ch && ch <= 'z')
+               || ch == '-' || ch == '_'))
+           return false;
+         ++dn;
        }
-       return (-1);
+      while (dn < label_end);
+    }
+  return true;
 }
 
-/*
- * Routines to insert/extract short/long's.
- */
-
-u_int16_t
-_getshort(msgp)
-       register const u_char *msgp;
+/* Return true if the binary domain name has a first labels which
+   starts with '-'.  */
+static inline bool
+binary_leading_dash (const unsigned char *dn)
 {
-       register u_int16_t u;
-
-       GETSHORT(u, msgp);
-       return (u);
+  return dn[0] > 0 && dn[1] == '-';
 }
 
-#ifdef NeXT
-/*
- * nExt machines have some funky library conventions, which we must maintain.
- */
-u_int16_t
-res_getshort(msgp)
-       register const u_char *msgp;
+/* Return 1 if res_hnok is a valid host name.  Labels must only
+   contain [0-9a-zA-Z_-] characters, and the name must not start with
+   a '-'.  The latter is to avoid confusion with program options.  */
+int
+res_hnok (const char *dn)
 {
-       return (_getshort(msgp));
+  unsigned char buf[NS_MAXCDNAME];
+  if (!printable_string (dn)
+      || ns_name_pton (dn, buf, sizeof (buf)) < 0
+      || binary_leading_dash (buf))
+    return 0;
+  return binary_hnok (buf);
 }
-#endif
+libresolv_hidden_def (res_hnok)
 
-u_int32_t
-_getlong(msgp)
-       register const u_char *msgp;
+/* Hostname-like (A, MX, WKS) owners can have "*" as their first label
+   but must otherwise be as a host name.  */
+int
+res_ownok (const char *dn)
 {
-       register u_int32_t u;
-
-       GETLONG(u, msgp);
-       return (u);
+  unsigned char buf[NS_MAXCDNAME];
+  if (!printable_string (dn)
+      || ns_name_pton (dn, buf, sizeof (buf)) < 0
+      || binary_leading_dash (buf))
+    return 0;
+  if (buf[0] == 1 && buf [1] == '*')
+    /* Skip over the leading "*." part.  */
+    return binary_hnok (buf + 2);
+  else
+    return binary_hnok (buf);
 }
 
-void
-#if defined(__STDC__) || defined(__cplusplus)
-__putshort(register u_int16_t s, register u_char *msgp)        /* must match proto */
-#else
-__putshort(s, msgp)
-       register u_int16_t s;
-       register u_char *msgp;
-#endif
+/* SOA RNAMEs and RP RNAMEs can have any byte in their first label,
+   but the rest of the name has to look like a host name.  */
+int
+res_mailok (const char *dn)
 {
-       PUTSHORT(s, msgp);
+  unsigned char buf[NS_MAXCDNAME];
+  if (!printable_string (dn)
+      || ns_name_pton (dn, buf, sizeof (buf)) < 0)
+    return 0;
+  unsigned char label_length = buf[0];
+  /* "." is a valid missing representation */
+  if (label_length == 0)
+    return 1;
+  /* Skip over the first label.  */
+  unsigned char *tail = buf + 1 + label_length;
+  if (*tail == 0)
+    /* More than one label is required (except for ".").  */
+    return 0;
+  return binary_hnok (tail);
 }
 
-void
-__putlong(l, msgp)
-       register u_int32_t l;
-       register u_char *msgp;
+/* Return 1 if DN is a syntactically valid domain name.  Empty names
+   are accepted.  */
+int
+res_dnok (const char *dn)
 {
-       PUTLONG(l, msgp);
+  unsigned char buf[NS_MAXCDNAME];
+  return printable_string (dn) && ns_name_pton (dn, buf, sizeof (buf)) >= 0;
 }
+libresolv_hidden_def (res_dnok)
 
-#ifdef ultrix
-/* ultrix 4.0 had some icky packaging in its libc.a.  alias for it here.
- * there is more gunk of this kind over in res_debug.c.
+/*
+ * This module must export the following externally-visible symbols:
+ *     ___putlong
+ *     ___putshort
+ *     __getlong
+ *     __getshort
+ * Note that one _ comes from C and the others come from us.
  */
-#undef putshort
-void
-#if defined(__STDC__) || defined(__cplusplus)
-putshort(register u_short s, register u_char *msgp)
-#else
-putshort(s, msgp)
-       register u_short s;
-       register u_char *msgp;
+void __putlong(uint32_t src, u_char *dst) { ns_put32(src, dst); }
+libresolv_hidden_def (__putlong)
+void __putshort(uint16_t src, u_char *dst) { ns_put16(src, dst); }
+libresolv_hidden_def (__putshort)
+uint32_t _getlong(const u_char *src) { return (ns_get32(src)); }
+uint16_t _getshort(const u_char *src) { return (ns_get16(src)); }
+\f
+
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libresolv, GLIBC_2_0, GLIBC_2_2)
+# undef dn_expand
+weak_alias (__dn_expand, dn_expand);
 #endif
-{
-       __putshort(s, msgp);
-}
-#undef putlong
-void
-putlong(l, msgp)
-       register u_int32_t l;
-       register u_char *msgp;
-{
-       __putlong(l, msgp);
-}
-#undef dn_skipname
-dn_skipname(comp_dn, eom)
-       const u_char *comp_dn, *eom;
-{
-       return (__dn_skipname(comp_dn, eom));
-}
-#endif /* Ultrix 4.0 hackery */