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