|
|
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;
|