]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - resolv/inet_pton.c
resolv: Do not send queries for non-host-names in nss_dns [BZ #24112]
[thirdparty/glibc.git] / resolv / inet_pton.c
index 4dcbad95c4df714f49a121d1946a4f703b95ebf4..5aeb8d46938d306e8d5d3c35140aafeb65bd0a82 100644 (file)
@@ -1,4 +1,22 @@
-/* Copyright (c) 1996 by Internet Software Consortium.
+/* Copyright (C) 1996-2019 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
+   <http://www.gnu.org/licenses/>.  */
+
+/*
+ * 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
  * SOFTWARE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char rcsid[] = "$Id$";
-#endif /* LIBC_SCCS and not lint */
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
 #include <arpa/inet.h>
 #include <arpa/nameser.h>
 #include <ctype.h>
-#include <string.h>
 #include <errno.h>
-#include <conf/portability.h>
+#include <netinet/in.h>
+#include <resolv/resolv-internal.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 
-/*
- * WARNING: Don't even consider trying to compile this on a system where
- * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
- */
+static int inet_pton4 (const char *src, const char *src_end, u_char *dst);
+static int inet_pton6 (const char *src, const char *src_end, u_char *dst);
 
-static int inet_pton4 (const char *src, u_char *dst) internal_function;
-static int inet_pton6 (const char *src, u_char *dst) internal_function;
-
-/* int
- * inet_pton(af, src, dst)
- *     convert from presentation format (which usually means ASCII printable)
- *     to network format (which is usually some kind of binary format).
- * return:
- *     1 if the address was valid for the specified address family
- *     0 if the address wasn't valid (`dst' is untouched in this case)
- *     -1 if some other error occurred (`dst' is untouched in this case, too)
- * author:
- *     Paul Vixie, 1996.
- */
 int
-inet_pton(af, src, dst)
-       int af;
-       const char *src;
-       void *dst;
+__inet_pton_length (int af, const char *src, size_t srclen, void *dst)
 {
-       switch (af) {
-       case AF_INET:
-               return (inet_pton4(src, dst));
-       case AF_INET6:
-               return (inet_pton6(src, dst));
-       default:
-               __set_errno (EAFNOSUPPORT);
-               return (-1);
-       }
-       /* NOTREACHED */
+  switch (af)
+    {
+    case AF_INET:
+      return inet_pton4 (src, src + srclen, dst);
+    case AF_INET6:
+      return inet_pton6 (src, src + srclen, dst);
+    default:
+      __set_errno (EAFNOSUPPORT);
+      return -1;
+    }
 }
+libc_hidden_def (__inet_pton_length)
 
-/* int
- * inet_pton4(src, dst)
- *     like inet_aton() but without all the hexadecimal and shorthand.
- * return:
- *     1 if `src' is a valid dotted quad, else 0.
- * notice:
- *     does not touch `dst' unless it's returning 1.
- * author:
- *     Paul Vixie, 1996.
- */
+/* Like __inet_pton_length, but use strlen (SRC) as the length of
+   SRC.  */
+int
+__inet_pton (int af, const char *src, void *dst)
+{
+  return __inet_pton_length (af, src, strlen (src), dst);
+}
+libc_hidden_def (__inet_pton)
+weak_alias (__inet_pton, inet_pton)
+libc_hidden_weak (inet_pton)
+
+/* Like inet_aton but without all the hexadecimal, octal and shorthand
+   (and trailing garbage is not ignored).  Return 1 if SRC is a valid
+   dotted quad, else 0.  This function does not touch DST unless it's
+   returning 1.
+   Author: Paul Vixie, 1996.  */
 static int
-internal_function
-inet_pton4(src, dst)
-       const char *src;
-       u_char *dst;
+inet_pton4 (const char *src, const char *end, unsigned char *dst)
 {
-       int saw_digit, octets, ch;
-       u_char tmp[INADDRSZ], *tp;
-
-       saw_digit = 0;
-       octets = 0;
-       *(tp = tmp) = 0;
-       while ((ch = *src++) != '\0') {
-
-               if (ch >= '0' && ch <= '9') {
-                       u_int new = *tp * 10 + (ch - '0');
-
-                       if (new > 255)
-                               return (0);
-                       *tp = new;
-                       if (! saw_digit) {
-                               if (++octets > 4)
-                                       return (0);
-                               saw_digit = 1;
-                       }
-               } else if (ch == '.' && saw_digit) {
-                       if (octets == 4)
-                               return (0);
-                       *++tp = 0;
-                       saw_digit = 0;
-               } else
-                       return (0);
-       }
-       if (octets < 4)
-               return (0);
+  int saw_digit, octets, ch;
+  unsigned char tmp[NS_INADDRSZ], *tp;
+
+  saw_digit = 0;
+  octets = 0;
+  *(tp = tmp) = 0;
+  while (src < end)
+    {
+      ch = *src++;
+      if (ch >= '0' && ch <= '9')
+        {
+          unsigned int new = *tp * 10 + (ch - '0');
 
-       memcpy(dst, tmp, INADDRSZ);
-       return (1);
+          if (saw_digit && *tp == 0)
+            return 0;
+          if (new > 255)
+            return 0;
+          *tp = new;
+          if (! saw_digit)
+            {
+              if (++octets > 4)
+                return 0;
+              saw_digit = 1;
+            }
+        }
+      else if (ch == '.' && saw_digit)
+        {
+          if (octets == 4)
+            return 0;
+          *++tp = 0;
+          saw_digit = 0;
+        }
+      else
+        return 0;
+    }
+  if (octets < 4)
+    return 0;
+  memcpy (dst, tmp, NS_INADDRSZ);
+  return 1;
 }
 
-/* int
- * inet_pton6(src, dst)
- *     convert presentation level address to network order binary form.
- * return:
- *     1 if `src' is a valid [RFC1884 2.2] address, else 0.
- * notice:
- *     (1) does not touch `dst' unless it's returning 1.
- *     (2) :: in a full address is silently ignored.
- * credit:
- *     inspired by Mark Andrews.
- * author:
- *     Paul Vixie, 1996.
- */
+/* Return the value of CH as a hexademical digit, or -1 if it is a
+   different type of character.  */
+static int
+hex_digit_value (char ch)
+{
+  if ('0' <= ch && ch <= '9')
+    return ch - '0';
+  if ('a' <= ch && ch <= 'f')
+    return ch - 'a' + 10;
+  if ('A' <= ch && ch <= 'F')
+    return ch - 'A' + 10;
+  return -1;
+}
+
+/* Convert presentation-level IPv6 address to network order binary
+   form.  Return 1 if SRC is a valid [RFC1884 2.2] address, else 0.
+   This function does not touch DST unless it's returning 1.
+   Author: Paul Vixie, 1996.  Inspired by Mark Andrews.  */
 static int
-internal_function
-inet_pton6(src, dst)
-       const char *src;
-       u_char *dst;
+inet_pton6 (const char *src, const char *src_endp, unsigned char *dst)
 {
-       static const char xdigits[] = "0123456789abcdef";
-       u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
-       const char *curtok;
-       int ch, saw_xdigit;
-       u_int val;
-
-       tp = memset(tmp, '\0', IN6ADDRSZ);
-       endp = tp + IN6ADDRSZ;
-       colonp = NULL;
-       /* Leading :: requires some special handling. */
-       if (*src == ':')
-               if (*++src != ':')
-                       return (0);
-       curtok = src;
-       saw_xdigit = 0;
-       val = 0;
-       while ((ch = tolower (*src++)) != '\0') {
-               const char *pch;
-
-               pch = strchr(xdigits, ch);
-               if (pch != NULL) {
-                       val <<= 4;
-                       val |= (pch - xdigits);
-                       if (val > 0xffff)
-                               return (0);
-                       saw_xdigit = 1;
-                       continue;
-               }
-               if (ch == ':') {
-                       curtok = src;
-                       if (!saw_xdigit) {
-                               if (colonp)
-                                       return (0);
-                               colonp = tp;
-                               continue;
-                       }
-                       if (tp + INT16SZ > endp)
-                               return (0);
-                       *tp++ = (u_char) (val >> 8) & 0xff;
-                       *tp++ = (u_char) val & 0xff;
-                       saw_xdigit = 0;
-                       val = 0;
-                       continue;
-               }
-               if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
-                   inet_pton4(curtok, tp) > 0) {
-                       tp += INADDRSZ;
-                       saw_xdigit = 0;
-                       break;  /* '\0' was seen by inet_pton4(). */
-               }
-               return (0);
+  unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+  const char *curtok;
+  int ch;
+  size_t xdigits_seen; /* Number of hex digits since colon.  */
+  unsigned int val;
+
+  tp = memset (tmp, '\0', NS_IN6ADDRSZ);
+  endp = tp + NS_IN6ADDRSZ;
+  colonp = NULL;
+
+  /* Leading :: requires some special handling.  */
+  if (src == src_endp)
+    return 0;
+  if (*src == ':')
+    {
+      ++src;
+      if (src == src_endp || *src != ':')
+        return 0;
+    }
+
+  curtok = src;
+  xdigits_seen = 0;
+  val = 0;
+  while (src < src_endp)
+    {
+      ch = *src++;
+      int digit = hex_digit_value (ch);
+      if (digit >= 0)
+       {
+         if (xdigits_seen == 4)
+           return 0;
+         val <<= 4;
+         val |= digit;
+         if (val > 0xffff)
+           return 0;
+         ++xdigits_seen;
+         continue;
        }
-       if (saw_xdigit) {
-               if (tp + INT16SZ > endp)
-                       return (0);
-               *tp++ = (u_char) (val >> 8) & 0xff;
-               *tp++ = (u_char) val & 0xff;
+      if (ch == ':')
+       {
+         curtok = src;
+         if (xdigits_seen == 0)
+           {
+             if (colonp)
+               return 0;
+             colonp = tp;
+             continue;
+           }
+         else if (src == src_endp)
+            return 0;
+         if (tp + NS_INT16SZ > endp)
+           return 0;
+         *tp++ = (unsigned char) (val >> 8) & 0xff;
+         *tp++ = (unsigned char) val & 0xff;
+         xdigits_seen = 0;
+         val = 0;
+         continue;
        }
-       if (colonp != NULL) {
-               /*
-                * Since some memmove()'s erroneously fail to handle
-                * overlapping regions, we'll do the shift by hand.
-                */
-               const int n = tp - colonp;
-               int i;
-
-               for (i = 1; i <= n; i++) {
-                       endp[- i] = colonp[n - i];
-                       colonp[n - i] = 0;
-               }
-               tp = endp;
+      if (ch == '.' && ((tp + NS_INADDRSZ) <= endp)
+          && inet_pton4 (curtok, src_endp, tp) > 0)
+       {
+         tp += NS_INADDRSZ;
+         xdigits_seen = 0;
+         break;  /* '\0' was seen by inet_pton4.  */
        }
-       if (tp != endp)
-               return (0);
-       memcpy(dst, tmp, IN6ADDRSZ);
-       return (1);
+      return 0;
+    }
+  if (xdigits_seen > 0)
+    {
+      if (tp + NS_INT16SZ > endp)
+       return 0;
+      *tp++ = (unsigned char) (val >> 8) & 0xff;
+      *tp++ = (unsigned char) val & 0xff;
+    }
+  if (colonp != NULL)
+    {
+      /* Replace :: with zeros.  */
+      if (tp == endp)
+        /* :: would expand to a zero-width field.  */
+        return 0;
+      size_t n = tp - colonp;
+      memmove (endp - n, colonp, n);
+      memset (colonp, 0, endp - n - colonp);
+      tp = endp;
+    }
+  if (tp != endp)
+    return 0;
+  memcpy (dst, tmp, NS_IN6ADDRSZ);
+  return 1;
 }