bdc76f
commit 108bc4049f8ae82710aec26a92ffdb4b439c83fd
bdc76f
Author: Florian Weimer <fweimer@redhat.com>
bdc76f
Date:   Mon Jan 21 21:26:03 2019 +0100
bdc76f
bdc76f
    CVE-2016-10739: getaddrinfo: Fully parse IPv4 address strings [BZ #20018]
bdc76f
    
bdc76f
    The IPv4 address parser in the getaddrinfo function is changed so that
bdc76f
    it does not ignore trailing whitespace and all characters after it.
bdc76f
    For backwards compatibility, the getaddrinfo function still recognizes
bdc76f
    legacy name syntax, such as 192.000.002.010 interpreted as 192.0.2.8
bdc76f
    (octal).
bdc76f
    
bdc76f
    This commit does not change the behavior of inet_addr and inet_aton.
bdc76f
    gethostbyname already had additional sanity checks (but is switched
bdc76f
    over to the new __inet_aton_exact function for completeness as well).
bdc76f
    
bdc76f
    To avoid sending the problematic query names over DNS, commit
bdc76f
    6ca53a2453598804a2559a548a08424fca96434a ("resolv: Do not send queries
bdc76f
    for non-host-names in nss_dns [BZ #24112]") is needed.
bdc76f
bdc76f
diff --git a/include/arpa/inet.h b/include/arpa/inet.h
bdc76f
index c3f28f2baaa2ed66..19aec74275069a45 100644
bdc76f
--- a/include/arpa/inet.h
bdc76f
+++ b/include/arpa/inet.h
bdc76f
@@ -1,10 +1,10 @@
bdc76f
 #include <inet/arpa/inet.h>
bdc76f
 
bdc76f
 #ifndef _ISOMAC
bdc76f
-extern int __inet_aton (const char *__cp, struct in_addr *__inp);
bdc76f
-libc_hidden_proto (__inet_aton)
bdc76f
+/* Variant of inet_aton which rejects trailing garbage.  */
bdc76f
+extern int __inet_aton_exact (const char *__cp, struct in_addr *__inp);
bdc76f
+libc_hidden_proto (__inet_aton_exact)
bdc76f
 
bdc76f
-libc_hidden_proto (inet_aton)
bdc76f
 libc_hidden_proto (inet_ntop)
bdc76f
 libc_hidden_proto (inet_pton)
bdc76f
 extern __typeof (inet_pton) __inet_pton;
bdc76f
diff --git a/nscd/gai.c b/nscd/gai.c
bdc76f
index 24bdfee1db3791e2..f57f396f574a6e52 100644
bdc76f
--- a/nscd/gai.c
bdc76f
+++ b/nscd/gai.c
bdc76f
@@ -19,7 +19,6 @@
bdc76f
 
bdc76f
 /* This file uses the getaddrinfo code but it compiles it without NSCD
bdc76f
    support.  We just need a few symbol renames.  */
bdc76f
-#define __inet_aton inet_aton
bdc76f
 #define __ioctl ioctl
bdc76f
 #define __getsockname getsockname
bdc76f
 #define __socket socket
bdc76f
diff --git a/nscd/gethstbynm3_r.c b/nscd/gethstbynm3_r.c
bdc76f
index 7beb9dce9f4b350c..f792c4fcd042d13d 100644
bdc76f
--- a/nscd/gethstbynm3_r.c
bdc76f
+++ b/nscd/gethstbynm3_r.c
bdc76f
@@ -38,8 +38,6 @@
bdc76f
 #define HAVE_LOOKUP_BUFFER	1
bdc76f
 #define HAVE_AF			1
bdc76f
 
bdc76f
-#define __inet_aton inet_aton
bdc76f
-
bdc76f
 /* We are nscd, so we don't want to be talking to ourselves.  */
bdc76f
 #undef	USE_NSCD
bdc76f
 
bdc76f
diff --git a/nss/digits_dots.c b/nss/digits_dots.c
bdc76f
index 39bff38865a1ac5b..5441bce16ea8b2e9 100644
bdc76f
--- a/nss/digits_dots.c
bdc76f
+++ b/nss/digits_dots.c
bdc76f
@@ -29,7 +29,6 @@
bdc76f
 #include "nsswitch.h"
bdc76f
 
bdc76f
 #ifdef USE_NSCD
bdc76f
-# define inet_aton __inet_aton
bdc76f
 # include <nscd/nscd_proto.h>
bdc76f
 #endif
bdc76f
 
bdc76f
@@ -160,7 +159,7 @@ __nss_hostname_digits_dots_context (struct resolv_context *ctx,
bdc76f
 		     255.255.255.255?  The test below will succeed
bdc76f
 		     spuriously... ???  */
bdc76f
 		  if (af == AF_INET)
bdc76f
-		    ok = __inet_aton (name, (struct in_addr *) host_addr);
bdc76f
+		    ok = __inet_aton_exact (name, (struct in_addr *) host_addr);
bdc76f
 		  else
bdc76f
 		    {
bdc76f
 		      assert (af == AF_INET6);
bdc76f
diff --git a/resolv/Makefile b/resolv/Makefile
bdc76f
index 56718654eeab85a3..72a0f196506ac489 100644
bdc76f
--- a/resolv/Makefile
bdc76f
+++ b/resolv/Makefile
bdc76f
@@ -34,6 +34,9 @@ routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \
bdc76f
 tests = tst-aton tst-leaks tst-inet_ntop
bdc76f
 xtests = tst-leaks2
bdc76f
 
bdc76f
+tests-internal += tst-inet_aton_exact
bdc76f
+
bdc76f
+
bdc76f
 generate := mtrace-tst-leaks.out tst-leaks.mtrace tst-leaks2.mtrace
bdc76f
 
bdc76f
 extra-libs := libresolv libnss_dns
bdc76f
@@ -54,8 +57,10 @@ tests += \
bdc76f
   tst-resolv-binary \
bdc76f
   tst-resolv-edns \
bdc76f
   tst-resolv-network \
bdc76f
+  tst-resolv-nondecimal \
bdc76f
   tst-resolv-res_init-multi \
bdc76f
   tst-resolv-search \
bdc76f
+  tst-resolv-trailing \
bdc76f
 
bdc76f
 # These tests need libdl.
bdc76f
 ifeq (yes,$(build-shared))
bdc76f
@@ -190,9 +195,11 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \
bdc76f
   $(shared-thread-library)
bdc76f
 $(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \
bdc76f
   $(shared-thread-library)
bdc76f
+$(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
bdc76f
 $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
bdc76f
 $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library)
bdc76f
 $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
bdc76f
+$(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library)
bdc76f
 $(objpfx)tst-resolv-threads: \
bdc76f
   $(libdl) $(objpfx)libresolv.so $(shared-thread-library)
bdc76f
 $(objpfx)tst-resolv-canonname: \
bdc76f
diff --git a/resolv/Versions b/resolv/Versions
bdc76f
index b05778d9654aa0f2..9a82704af75f789b 100644
bdc76f
--- a/resolv/Versions
bdc76f
+++ b/resolv/Versions
bdc76f
@@ -27,6 +27,7 @@ libc {
bdc76f
     __h_errno; __resp;
bdc76f
 
bdc76f
     __res_iclose;
bdc76f
+    __inet_aton_exact;
bdc76f
     __inet_pton_length;
bdc76f
     __resolv_context_get;
bdc76f
     __resolv_context_get_preinit;
bdc76f
diff --git a/resolv/inet_addr.c b/resolv/inet_addr.c
bdc76f
index 32f58b0e13598b32..41b6166a5bd5a44b 100644
bdc76f
--- a/resolv/inet_addr.c
bdc76f
+++ b/resolv/inet_addr.c
bdc76f
@@ -96,26 +96,14 @@
bdc76f
 #include <limits.h>
bdc76f
 #include <errno.h>
bdc76f
 
bdc76f
-/* ASCII IPv4 Internet address interpretation routine.  The value
bdc76f
-   returned is in network order.  */
bdc76f
-in_addr_t
bdc76f
-__inet_addr (const char *cp)
bdc76f
-{
bdc76f
-  struct in_addr val;
bdc76f
-
bdc76f
-  if (__inet_aton (cp, &val))
bdc76f
-    return val.s_addr;
bdc76f
-  return INADDR_NONE;
bdc76f
-}
bdc76f
-weak_alias (__inet_addr, inet_addr)
bdc76f
-
bdc76f
 /* Check whether "cp" is a valid ASCII representation of an IPv4
bdc76f
    Internet address and convert it to a binary address.  Returns 1 if
bdc76f
    the address is valid, 0 if not.  This replaces inet_addr, the
bdc76f
    return value from which cannot distinguish between failure and a
bdc76f
-   local broadcast address.  */
bdc76f
-int
bdc76f
-__inet_aton (const char *cp, struct in_addr *addr)
bdc76f
+   local broadcast address.  Write a pointer to the first
bdc76f
+   non-converted character to *endp.  */
bdc76f
+static int
bdc76f
+inet_aton_end (const char *cp, struct in_addr *addr, const char **endp)
bdc76f
 {
bdc76f
   static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff };
bdc76f
   in_addr_t val;
bdc76f
@@ -180,6 +168,7 @@ __inet_aton (const char *cp, struct in_addr *addr)
bdc76f
 
bdc76f
   if (addr != NULL)
bdc76f
     addr->s_addr = res.word | htonl (val);
bdc76f
+  *endp = cp;
bdc76f
 
bdc76f
   __set_errno (saved_errno);
bdc76f
   return 1;
bdc76f
@@ -188,6 +177,41 @@ __inet_aton (const char *cp, struct in_addr *addr)
bdc76f
   __set_errno (saved_errno);
bdc76f
   return 0;
bdc76f
 }
bdc76f
-weak_alias (__inet_aton, inet_aton)
bdc76f
-libc_hidden_def (__inet_aton)
bdc76f
-libc_hidden_weak (inet_aton)
bdc76f
+
bdc76f
+int
bdc76f
+__inet_aton_exact (const char *cp, struct in_addr *addr)
bdc76f
+{
bdc76f
+  struct in_addr val;
bdc76f
+  const char *endp;
bdc76f
+  /* Check that inet_aton_end parsed the entire string.  */
bdc76f
+  if (inet_aton_end (cp, &val, &endp) != 0 && *endp == 0)
bdc76f
+    {
bdc76f
+      *addr = val;
bdc76f
+      return 1;
bdc76f
+    }
bdc76f
+  else
bdc76f
+    return 0;
bdc76f
+}
bdc76f
+libc_hidden_def (__inet_aton_exact)
bdc76f
+
bdc76f
+/* inet_aton ignores trailing garbage.  */
bdc76f
+int
bdc76f
+__inet_aton_ignore_trailing (const char *cp, struct in_addr *addr)
bdc76f
+{
bdc76f
+  const char *endp;
bdc76f
+  return  inet_aton_end (cp, addr, &endp);
bdc76f
+}
bdc76f
+weak_alias (__inet_aton_ignore_trailing, inet_aton)
bdc76f
+
bdc76f
+/* ASCII IPv4 Internet address interpretation routine.  The value
bdc76f
+   returned is in network order.  */
bdc76f
+in_addr_t
bdc76f
+__inet_addr (const char *cp)
bdc76f
+{
bdc76f
+  struct in_addr val;
bdc76f
+  const char *endp;
bdc76f
+  if (inet_aton_end (cp, &val, &endp))
bdc76f
+    return val.s_addr;
bdc76f
+  return INADDR_NONE;
bdc76f
+}
bdc76f
+weak_alias (__inet_addr, inet_addr)
bdc76f
diff --git a/resolv/res_init.c b/resolv/res_init.c
bdc76f
index f5e52cbbb9377762..94743a252e39d64a 100644
bdc76f
--- a/resolv/res_init.c
bdc76f
+++ b/resolv/res_init.c
bdc76f
@@ -399,8 +399,16 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
bdc76f
               cp = parser->buffer + sizeof ("nameserver") - 1;
bdc76f
               while (*cp == ' ' || *cp == '\t')
bdc76f
                 cp++;
bdc76f
+
bdc76f
+              /* Ignore trailing contents on the name server line.  */
bdc76f
+              {
bdc76f
+                char *el;
bdc76f
+                if ((el = strpbrk (cp, " \t\n")) != NULL)
bdc76f
+                  *el = '\0';
bdc76f
+              }
bdc76f
+
bdc76f
               struct sockaddr *sa;
bdc76f
-              if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a))
bdc76f
+              if ((*cp != '\0') && (*cp != '\n') && __inet_aton_exact (cp, &a))
bdc76f
                 {
bdc76f
                   sa = allocate_address_v4 (a, NAMESERVER_PORT);
bdc76f
                   if (sa == NULL)
bdc76f
@@ -410,9 +418,6 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
bdc76f
                 {
bdc76f
                   struct in6_addr a6;
bdc76f
                   char *el;
bdc76f
-
bdc76f
-                  if ((el = strpbrk (cp, " \t\n")) != NULL)
bdc76f
-                    *el = '\0';
bdc76f
                   if ((el = strchr (cp, SCOPE_DELIMITER)) != NULL)
bdc76f
                     *el = '\0';
bdc76f
                   if ((*cp != '\0') && (__inet_pton (AF_INET6, cp, &a6) > 0))
bdc76f
@@ -472,7 +477,7 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
bdc76f
                   char separator = *cp;
bdc76f
                   *cp = 0;
bdc76f
                   struct resolv_sortlist_entry e;
bdc76f
-                  if (__inet_aton (net, &a))
bdc76f
+                  if (__inet_aton_exact (net, &a))
bdc76f
                     {
bdc76f
                       e.addr = a;
bdc76f
                       if (is_sort_mask (separator))
bdc76f
@@ -484,7 +489,7 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
bdc76f
                             cp++;
bdc76f
                           separator = *cp;
bdc76f
                           *cp = 0;
bdc76f
-                          if (__inet_aton (net, &a))
bdc76f
+                          if (__inet_aton_exact (net, &a))
bdc76f
                             e.mask = a.s_addr;
bdc76f
                           else
bdc76f
                             e.mask = net_mask (e.addr);
bdc76f
diff --git a/resolv/tst-aton.c b/resolv/tst-aton.c
bdc76f
index 08110a007af909ff..eb734d7758d6ed87 100644
bdc76f
--- a/resolv/tst-aton.c
bdc76f
+++ b/resolv/tst-aton.c
bdc76f
@@ -1,11 +1,29 @@
bdc76f
+/* Test legacy IPv4 text-to-address function inet_aton.
bdc76f
+   Copyright (C) 1998-2019 Free Software Foundation, Inc.
bdc76f
+   This file is part of the GNU C Library.
bdc76f
+
bdc76f
+   The GNU C Library is free software; you can redistribute it and/or
bdc76f
+   modify it under the terms of the GNU Lesser General Public
bdc76f
+   License as published by the Free Software Foundation; either
bdc76f
+   version 2.1 of the License, or (at your option) any later version.
bdc76f
+
bdc76f
+   The GNU C Library is distributed in the hope that it will be useful,
bdc76f
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
bdc76f
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
bdc76f
+   Lesser General Public License for more details.
bdc76f
+
bdc76f
+   You should have received a copy of the GNU Lesser General Public
bdc76f
+   License along with the GNU C Library; if not, see
bdc76f
+   <http://www.gnu.org/licenses/>.  */
bdc76f
+
bdc76f
+#include <array_length.h>
bdc76f
 #include <stdio.h>
bdc76f
 #include <stdint.h>
bdc76f
 #include <sys/socket.h>
bdc76f
 #include <netinet/in.h>
bdc76f
 #include <arpa/inet.h>
bdc76f
 
bdc76f
-
bdc76f
-static struct tests
bdc76f
+static const struct tests
bdc76f
 {
bdc76f
   const char *input;
bdc76f
   int valid;
bdc76f
@@ -16,6 +34,7 @@ static struct tests
bdc76f
   { "-1", 0, 0 },
bdc76f
   { "256", 1, 0x00000100 },
bdc76f
   { "256.", 0, 0 },
bdc76f
+  { "255a", 0, 0 },
bdc76f
   { "256a", 0, 0 },
bdc76f
   { "0x100", 1, 0x00000100 },
bdc76f
   { "0200.0x123456", 1, 0x80123456 },
bdc76f
@@ -40,7 +59,12 @@ static struct tests
bdc76f
   { "1.2.256.4", 0, 0 },
bdc76f
   { "1.2.3.0x100", 0, 0 },
bdc76f
   { "323543357756889", 0, 0 },
bdc76f
-  { "10.1.2.3.4", 0, 0},
bdc76f
+  { "10.1.2.3.4", 0, 0 },
bdc76f
+  { "192.0.2.1", 1, 0xc0000201 },
bdc76f
+  { "192.0.2.2\nX", 1, 0xc0000202 },
bdc76f
+  { "192.0.2.3 Y", 1, 0xc0000203 },
bdc76f
+  { "192.0.2.3Z", 0, 0 },
bdc76f
+  { "192.000.002.010", 1, 0xc0000208 },
bdc76f
 };
bdc76f
 
bdc76f
 
bdc76f
@@ -50,7 +74,7 @@ do_test (void)
bdc76f
   int result = 0;
bdc76f
   size_t cnt;
bdc76f
 
bdc76f
-  for (cnt = 0; cnt < sizeof (tests) / sizeof (tests[0]); ++cnt)
bdc76f
+  for (cnt = 0; cnt < array_length (tests); ++cnt)
bdc76f
     {
bdc76f
       struct in_addr addr;
bdc76f
 
bdc76f
@@ -73,5 +97,4 @@ do_test (void)
bdc76f
   return result;
bdc76f
 }
bdc76f
 
bdc76f
-#define TEST_FUNCTION do_test ()
bdc76f
-#include "../test-skeleton.c"
bdc76f
+#include <support/test-driver.c>
bdc76f
diff --git a/resolv/tst-inet_aton_exact.c b/resolv/tst-inet_aton_exact.c
bdc76f
new file mode 100644
bdc76f
index 0000000000000000..0fdfa3d6aa9aef91
bdc76f
--- /dev/null
bdc76f
+++ b/resolv/tst-inet_aton_exact.c
bdc76f
@@ -0,0 +1,47 @@
bdc76f
+/* Test internal legacy IPv4 text-to-address function __inet_aton_exact.
bdc76f
+   Copyright (C) 2019 Free Software Foundation, Inc.
bdc76f
+   This file is part of the GNU C Library.
bdc76f
+
bdc76f
+   The GNU C Library is free software; you can redistribute it and/or
bdc76f
+   modify it under the terms of the GNU Lesser General Public
bdc76f
+   License as published by the Free Software Foundation; either
bdc76f
+   version 2.1 of the License, or (at your option) any later version.
bdc76f
+
bdc76f
+   The GNU C Library is distributed in the hope that it will be useful,
bdc76f
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
bdc76f
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
bdc76f
+   Lesser General Public License for more details.
bdc76f
+
bdc76f
+   You should have received a copy of the GNU Lesser General Public
bdc76f
+   License along with the GNU C Library; if not, see
bdc76f
+   <http://www.gnu.org/licenses/>.  */
bdc76f
+
bdc76f
+#include <arpa/inet.h>
bdc76f
+#include <support/check.h>
bdc76f
+
bdc76f
+static int
bdc76f
+do_test (void)
bdc76f
+{
bdc76f
+  struct in_addr addr = { };
bdc76f
+
bdc76f
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.1", &addr), 1);
bdc76f
+  TEST_COMPARE (ntohl (addr.s_addr), 0xC0000201);
bdc76f
+
bdc76f
+  TEST_COMPARE (__inet_aton_exact ("192.000.002.010", &addr), 1);
bdc76f
+  TEST_COMPARE (ntohl (addr.s_addr), 0xC0000208);
bdc76f
+  TEST_COMPARE (__inet_aton_exact ("0xC0000234", &addr), 1);
bdc76f
+  TEST_COMPARE (ntohl (addr.s_addr), 0xC0000234);
bdc76f
+
bdc76f
+  /* Trailing content is not accepted.  */
bdc76f
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.2X", &addr), 0);
bdc76f
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.3 Y", &addr), 0);
bdc76f
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.4\nZ", &addr), 0);
bdc76f
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.5\tT", &addr), 0);
bdc76f
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.6 Y", &addr), 0);
bdc76f
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.7\n", &addr), 0);
bdc76f
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.8\t", &addr), 0);
bdc76f
+
bdc76f
+  return 0;
bdc76f
+}
bdc76f
+
bdc76f
+#include <support/test-driver.c>
bdc76f
diff --git a/resolv/tst-resolv-nondecimal.c b/resolv/tst-resolv-nondecimal.c
bdc76f
new file mode 100644
bdc76f
index 0000000000000000..a0df6f332ae8faf7
bdc76f
--- /dev/null
bdc76f
+++ b/resolv/tst-resolv-nondecimal.c
bdc76f
@@ -0,0 +1,139 @@
bdc76f
+/* Test name resolution behavior for octal, hexadecimal IPv4 addresses.
bdc76f
+   Copyright (C) 2019 Free Software Foundation, Inc.
bdc76f
+   This file is part of the GNU C Library.
bdc76f
+
bdc76f
+   The GNU C Library is free software; you can redistribute it and/or
bdc76f
+   modify it under the terms of the GNU Lesser General Public
bdc76f
+   License as published by the Free Software Foundation; either
bdc76f
+   version 2.1 of the License, or (at your option) any later version.
bdc76f
+
bdc76f
+   The GNU C Library is distributed in the hope that it will be useful,
bdc76f
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
bdc76f
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
bdc76f
+   Lesser General Public License for more details.
bdc76f
+
bdc76f
+   You should have received a copy of the GNU Lesser General Public
bdc76f
+   License along with the GNU C Library; if not, see
bdc76f
+   <http://www.gnu.org/licenses/>.  */
bdc76f
+
bdc76f
+#include <netdb.h>
bdc76f
+#include <stdlib.h>
bdc76f
+#include <support/check.h>
bdc76f
+#include <support/check_nss.h>
bdc76f
+#include <support/resolv_test.h>
bdc76f
+#include <support/support.h>
bdc76f
+
bdc76f
+static void
bdc76f
+response (const struct resolv_response_context *ctx,
bdc76f
+          struct resolv_response_builder *b,
bdc76f
+          const char *qname, uint16_t qclass, uint16_t qtype)
bdc76f
+{
bdc76f
+  /* The tests are not supposed send any DNS queries.  */
bdc76f
+  FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype);
bdc76f
+}
bdc76f
+
bdc76f
+static void
bdc76f
+run_query_addrinfo (const char *query, const char *address)
bdc76f
+{
bdc76f
+  char *quoted_query = support_quote_string (query);
bdc76f
+
bdc76f
+  struct addrinfo *ai;
bdc76f
+  struct addrinfo hints =
bdc76f
+    {
bdc76f
+     .ai_socktype = SOCK_STREAM,
bdc76f
+     .ai_protocol = IPPROTO_TCP,
bdc76f
+    };
bdc76f
+
bdc76f
+  char *context = xasprintf ("getaddrinfo \"%s\" AF_INET", quoted_query);
bdc76f
+  char *expected = xasprintf ("address: STREAM/TCP %s 80\n", address);
bdc76f
+  hints.ai_family = AF_INET;
bdc76f
+  int ret = getaddrinfo (query, "80", &hints, &ai;;
bdc76f
+  check_addrinfo (context, ai, ret, expected);
bdc76f
+  if (ret == 0)
bdc76f
+    freeaddrinfo (ai);
bdc76f
+  free (context);
bdc76f
+
bdc76f
+  context = xasprintf ("getaddrinfo \"%s\" AF_UNSPEC", quoted_query);
bdc76f
+  hints.ai_family = AF_UNSPEC;
bdc76f
+  ret = getaddrinfo (query, "80", &hints, &ai;;
bdc76f
+  check_addrinfo (context, ai, ret, expected);
bdc76f
+  if (ret == 0)
bdc76f
+    freeaddrinfo (ai);
bdc76f
+  free (expected);
bdc76f
+  free (context);
bdc76f
+
bdc76f
+  context = xasprintf ("getaddrinfo \"%s\" AF_INET6", quoted_query);
bdc76f
+  expected = xasprintf ("flags: AI_V4MAPPED\n"
bdc76f
+                        "address: STREAM/TCP ::ffff:%s 80\n",
bdc76f
+                        address);
bdc76f
+  hints.ai_family = AF_INET6;
bdc76f
+  hints.ai_flags = AI_V4MAPPED;
bdc76f
+  ret = getaddrinfo (query, "80", &hints, &ai;;
bdc76f
+  check_addrinfo (context, ai, ret, expected);
bdc76f
+  if (ret == 0)
bdc76f
+    freeaddrinfo (ai);
bdc76f
+  free (expected);
bdc76f
+  free (context);
bdc76f
+
bdc76f
+  free (quoted_query);
bdc76f
+}
bdc76f
+
bdc76f
+static void
bdc76f
+run_query (const char *query, const char *address)
bdc76f
+{
bdc76f
+  char *quoted_query = support_quote_string (query);
bdc76f
+  char *context = xasprintf ("gethostbyname (\"%s\")", quoted_query);
bdc76f
+  char *expected = xasprintf ("name: %s\n"
bdc76f
+                              "address: %s\n", query, address);
bdc76f
+  check_hostent (context, gethostbyname (query), expected);
bdc76f
+  free (context);
bdc76f
+
bdc76f
+  context = xasprintf ("gethostbyname_r \"%s\"", quoted_query);
bdc76f
+  struct hostent storage;
bdc76f
+  char buf[4096];
bdc76f
+  struct hostent *e = NULL;
bdc76f
+  TEST_COMPARE (gethostbyname_r (query, &storage, buf, sizeof (buf),
bdc76f
+                                 &e, &h_errno), 0);
bdc76f
+  check_hostent (context, e, expected);
bdc76f
+  free (context);
bdc76f
+
bdc76f
+  context = xasprintf ("gethostbyname2 (\"%s\", AF_INET)", quoted_query);
bdc76f
+  check_hostent (context, gethostbyname2 (query, AF_INET), expected);
bdc76f
+  free (context);
bdc76f
+
bdc76f
+  context = xasprintf ("gethostbyname2_r \"%s\" AF_INET", quoted_query);
bdc76f
+  e = NULL;
bdc76f
+  TEST_COMPARE (gethostbyname2_r (query, AF_INET, &storage, buf, sizeof (buf),
bdc76f
+                                  &e, &h_errno), 0);
bdc76f
+  check_hostent (context, e, expected);
bdc76f
+  free (context);
bdc76f
+  free (expected);
bdc76f
+
bdc76f
+  free (quoted_query);
bdc76f
+
bdc76f
+  /* The gethostbyname tests are always valid for getaddrinfo, but not
bdc76f
+     vice versa.  */
bdc76f
+  run_query_addrinfo (query, address);
bdc76f
+}
bdc76f
+
bdc76f
+static int
bdc76f
+do_test (void)
bdc76f
+{
bdc76f
+  struct resolv_test *aux = resolv_test_start
bdc76f
+    ((struct resolv_redirect_config)
bdc76f
+     {
bdc76f
+       .response_callback = response,
bdc76f
+     });
bdc76f
+
bdc76f
+  run_query ("192.000.002.010", "192.0.2.8");
bdc76f
+
bdc76f
+  /* Hexadecimal numbers are not accepted by gethostbyname.  */
bdc76f
+  run_query_addrinfo ("0xc0000210", "192.0.2.16");
bdc76f
+  run_query_addrinfo ("192.0x234", "192.0.2.52");
bdc76f
+
bdc76f
+  resolv_test_end (aux);
bdc76f
+
bdc76f
+  return 0;
bdc76f
+}
bdc76f
+
bdc76f
+#include <support/test-driver.c>
bdc76f
diff --git a/resolv/tst-resolv-trailing.c b/resolv/tst-resolv-trailing.c
bdc76f
new file mode 100644
bdc76f
index 0000000000000000..7504bdae572ed8d0
bdc76f
--- /dev/null
bdc76f
+++ b/resolv/tst-resolv-trailing.c
bdc76f
@@ -0,0 +1,136 @@
bdc76f
+/* Test name resolution behavior with trailing characters.
bdc76f
+   Copyright (C) 2019 Free Software Foundation, Inc.
bdc76f
+   This file is part of the GNU C Library.
bdc76f
+
bdc76f
+   The GNU C Library is free software; you can redistribute it and/or
bdc76f
+   modify it under the terms of the GNU Lesser General Public
bdc76f
+   License as published by the Free Software Foundation; either
bdc76f
+   version 2.1 of the License, or (at your option) any later version.
bdc76f
+
bdc76f
+   The GNU C Library is distributed in the hope that it will be useful,
bdc76f
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
bdc76f
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
bdc76f
+   Lesser General Public License for more details.
bdc76f
+
bdc76f
+   You should have received a copy of the GNU Lesser General Public
bdc76f
+   License along with the GNU C Library; if not, see
bdc76f
+   <http://www.gnu.org/licenses/>.  */
bdc76f
+
bdc76f
+#include <array_length.h>
bdc76f
+#include <netdb.h>
bdc76f
+#include <support/check.h>
bdc76f
+#include <support/check_nss.h>
bdc76f
+#include <support/resolv_test.h>
bdc76f
+#include <support/support.h>
bdc76f
+
bdc76f
+static void
bdc76f
+response (const struct resolv_response_context *ctx,
bdc76f
+          struct resolv_response_builder *b,
bdc76f
+          const char *qname, uint16_t qclass, uint16_t qtype)
bdc76f
+{
bdc76f
+  /* The tests are not supposed send any DNS queries.  */
bdc76f
+  FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype);
bdc76f
+}
bdc76f
+
bdc76f
+static int
bdc76f
+do_test (void)
bdc76f
+{
bdc76f
+  struct resolv_test *aux = resolv_test_start
bdc76f
+    ((struct resolv_redirect_config)
bdc76f
+     {
bdc76f
+       .response_callback = response,
bdc76f
+     });
bdc76f
+
bdc76f
+  static const char *const queries[] =
bdc76f
+    {
bdc76f
+     "192.0.2.1 ",
bdc76f
+     "192.0.2.2\t",
bdc76f
+     "192.0.2.3\n",
bdc76f
+     "192.0.2.4 X",
bdc76f
+     "192.0.2.5\tY",
bdc76f
+     "192.0.2.6\nZ",
bdc76f
+     "192.0.2. ",
bdc76f
+     "192.0.2.\t",
bdc76f
+     "192.0.2.\n",
bdc76f
+     "192.0.2. X",
bdc76f
+     "192.0.2.\tY",
bdc76f
+     "192.0.2.\nZ",
bdc76f
+     "2001:db8::1 ",
bdc76f
+     "2001:db8::2\t",
bdc76f
+     "2001:db8::3\n",
bdc76f
+     "2001:db8::4 X",
bdc76f
+     "2001:db8::5\tY",
bdc76f
+     "2001:db8::6\nZ",
bdc76f
+    };
bdc76f
+  for (size_t query_idx = 0; query_idx < array_length (queries); ++query_idx)
bdc76f
+    {
bdc76f
+      const char *query = queries[query_idx];
bdc76f
+      struct hostent storage;
bdc76f
+      char buf[4096];
bdc76f
+      struct hostent *e;
bdc76f
+
bdc76f
+      h_errno = 0;
bdc76f
+      TEST_VERIFY (gethostbyname (query) == NULL);
bdc76f
+      TEST_COMPARE (h_errno, HOST_NOT_FOUND);
bdc76f
+
bdc76f
+      h_errno = 0;
bdc76f
+      e = NULL;
bdc76f
+      TEST_COMPARE (gethostbyname_r (query, &storage, buf, sizeof (buf),
bdc76f
+                                     &e, &h_errno), 0);
bdc76f
+      TEST_VERIFY (e == NULL);
bdc76f
+      TEST_COMPARE (h_errno, HOST_NOT_FOUND);
bdc76f
+
bdc76f
+      h_errno = 0;
bdc76f
+      TEST_VERIFY (gethostbyname2 (query, AF_INET) == NULL);
bdc76f
+      TEST_COMPARE (h_errno, HOST_NOT_FOUND);
bdc76f
+
bdc76f
+      h_errno = 0;
bdc76f
+      e = NULL;
bdc76f
+      TEST_COMPARE (gethostbyname2_r (query, AF_INET,
bdc76f
+                                      &storage, buf, sizeof (buf),
bdc76f
+                                     &e, &h_errno), 0);
bdc76f
+      TEST_VERIFY (e == NULL);
bdc76f
+      TEST_COMPARE (h_errno, HOST_NOT_FOUND);
bdc76f
+
bdc76f
+      h_errno = 0;
bdc76f
+      TEST_VERIFY (gethostbyname2 (query, AF_INET6) == NULL);
bdc76f
+      TEST_COMPARE (h_errno, HOST_NOT_FOUND);
bdc76f
+
bdc76f
+      h_errno = 0;
bdc76f
+      e = NULL;
bdc76f
+      TEST_COMPARE (gethostbyname2_r (query, AF_INET6,
bdc76f
+                                      &storage, buf, sizeof (buf),
bdc76f
+                                     &e, &h_errno), 0);
bdc76f
+      TEST_VERIFY (e == NULL);
bdc76f
+      TEST_COMPARE (h_errno, HOST_NOT_FOUND);
bdc76f
+
bdc76f
+      static const int gai_flags[] =
bdc76f
+        {
bdc76f
+         0,
bdc76f
+         AI_ADDRCONFIG,
bdc76f
+         AI_NUMERICHOST,
bdc76f
+         AI_IDN,
bdc76f
+         AI_IDN | AI_NUMERICHOST,
bdc76f
+         AI_V4MAPPED,
bdc76f
+         AI_V4MAPPED | AI_NUMERICHOST,
bdc76f
+        };
bdc76f
+      for (size_t gai_flags_idx; gai_flags_idx < array_length (gai_flags);
bdc76f
+             ++gai_flags_idx)
bdc76f
+        {
bdc76f
+          struct addrinfo hints = { .ai_flags = gai_flags[gai_flags_idx], };
bdc76f
+          struct addrinfo *ai;
bdc76f
+          hints.ai_family = AF_INET;
bdc76f
+          TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME);
bdc76f
+          hints.ai_family = AF_INET6;
bdc76f
+          TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME);
bdc76f
+          hints.ai_family = AF_UNSPEC;
bdc76f
+          TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME);
bdc76f
+        }
bdc76f
+    };
bdc76f
+
bdc76f
+  resolv_test_end (aux);
bdc76f
+
bdc76f
+  return 0;
bdc76f
+}
bdc76f
+
bdc76f
+#include <support/test-driver.c>
bdc76f
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
bdc76f
index 00e0d94a8f5bb30d..6a5805c9e63a257c 100644
bdc76f
--- a/sysdeps/posix/getaddrinfo.c
bdc76f
+++ b/sysdeps/posix/getaddrinfo.c
bdc76f
@@ -488,7 +488,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
bdc76f
 	  malloc_name = true;
bdc76f
 	}
bdc76f
 
bdc76f
-      if (__inet_aton (name, (struct in_addr *) at->addr) != 0)
bdc76f
+      if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
bdc76f
 	{
bdc76f
 	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
bdc76f
 	    at->family = AF_INET;