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