diff options
Diffstat (limited to 'resolv')
-rw-r--r-- | resolv/Makefile | 7 | ||||
-rw-r--r-- | resolv/Versions | 1 | ||||
-rw-r--r-- | resolv/inet_addr.c | 62 | ||||
-rw-r--r-- | resolv/res_init.c | 17 | ||||
-rw-r--r-- | resolv/tst-aton.c | 35 | ||||
-rw-r--r-- | resolv/tst-inet_aton_exact.c | 47 | ||||
-rw-r--r-- | resolv/tst-resolv-nondecimal.c | 139 | ||||
-rw-r--r-- | resolv/tst-resolv-trailing.c | 136 |
8 files changed, 413 insertions, 31 deletions
diff --git a/resolv/Makefile b/resolv/Makefile index 450e171b01..8f22e6a154 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -34,6 +34,9 @@ routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \ tests = tst-aton tst-leaks tst-inet_ntop xtests = tst-leaks2 +tests-internal += tst-inet_aton_exact + + generate := mtrace-tst-leaks.out tst-leaks.mtrace tst-leaks2.mtrace extra-libs := libresolv libnss_dns @@ -54,8 +57,10 @@ tests += \ tst-resolv-binary \ tst-resolv-edns \ tst-resolv-network \ + tst-resolv-nondecimal \ tst-resolv-res_init-multi \ tst-resolv-search \ + tst-resolv-trailing \ # These tests need libdl. ifeq (yes,$(build-shared)) @@ -190,9 +195,11 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \ $(shared-thread-library) $(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \ $(shared-thread-library) +$(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library) +$(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-threads: \ $(libdl) $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-canonname: \ diff --git a/resolv/Versions b/resolv/Versions index b05778d965..9a82704af7 100644 --- a/resolv/Versions +++ b/resolv/Versions @@ -27,6 +27,7 @@ libc { __h_errno; __resp; __res_iclose; + __inet_aton_exact; __inet_pton_length; __resolv_context_get; __resolv_context_get_preinit; diff --git a/resolv/inet_addr.c b/resolv/inet_addr.c index 32f58b0e13..41b6166a5b 100644 --- a/resolv/inet_addr.c +++ b/resolv/inet_addr.c @@ -96,26 +96,14 @@ #include <limits.h> #include <errno.h> -/* ASCII IPv4 Internet address interpretation routine. The value - returned is in network order. */ -in_addr_t -__inet_addr (const char *cp) -{ - struct in_addr val; - - if (__inet_aton (cp, &val)) - return val.s_addr; - return INADDR_NONE; -} -weak_alias (__inet_addr, inet_addr) - /* Check whether "cp" is a valid ASCII representation of an IPv4 Internet address and convert it to a binary address. Returns 1 if the address is valid, 0 if not. This replaces inet_addr, the return value from which cannot distinguish between failure and a - local broadcast address. */ -int -__inet_aton (const char *cp, struct in_addr *addr) + local broadcast address. Write a pointer to the first + non-converted character to *endp. */ +static int +inet_aton_end (const char *cp, struct in_addr *addr, const char **endp) { static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; in_addr_t val; @@ -180,6 +168,7 @@ __inet_aton (const char *cp, struct in_addr *addr) if (addr != NULL) addr->s_addr = res.word | htonl (val); + *endp = cp; __set_errno (saved_errno); return 1; @@ -188,6 +177,41 @@ __inet_aton (const char *cp, struct in_addr *addr) __set_errno (saved_errno); return 0; } -weak_alias (__inet_aton, inet_aton) -libc_hidden_def (__inet_aton) -libc_hidden_weak (inet_aton) + +int +__inet_aton_exact (const char *cp, struct in_addr *addr) +{ + struct in_addr val; + const char *endp; + /* Check that inet_aton_end parsed the entire string. */ + if (inet_aton_end (cp, &val, &endp) != 0 && *endp == 0) + { + *addr = val; + return 1; + } + else + return 0; +} +libc_hidden_def (__inet_aton_exact) + +/* inet_aton ignores trailing garbage. */ +int +__inet_aton_ignore_trailing (const char *cp, struct in_addr *addr) +{ + const char *endp; + return inet_aton_end (cp, addr, &endp); +} +weak_alias (__inet_aton_ignore_trailing, inet_aton) + +/* ASCII IPv4 Internet address interpretation routine. The value + returned is in network order. */ +in_addr_t +__inet_addr (const char *cp) +{ + struct in_addr val; + const char *endp; + if (inet_aton_end (cp, &val, &endp)) + return val.s_addr; + return INADDR_NONE; +} +weak_alias (__inet_addr, inet_addr) diff --git a/resolv/res_init.c b/resolv/res_init.c index 58c563898e..265e3cc6e3 100644 --- a/resolv/res_init.c +++ b/resolv/res_init.c @@ -399,8 +399,16 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) cp = parser->buffer + sizeof ("nameserver") - 1; while (*cp == ' ' || *cp == '\t') cp++; + + /* Ignore trailing contents on the name server line. */ + { + char *el; + if ((el = strpbrk (cp, " \t\n")) != NULL) + *el = '\0'; + } + struct sockaddr *sa; - if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a)) + if ((*cp != '\0') && (*cp != '\n') && __inet_aton_exact (cp, &a)) { sa = allocate_address_v4 (a, NAMESERVER_PORT); if (sa == NULL) @@ -410,9 +418,6 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) { struct in6_addr a6; char *el; - - if ((el = strpbrk (cp, " \t\n")) != NULL) - *el = '\0'; if ((el = strchr (cp, SCOPE_DELIMITER)) != NULL) *el = '\0'; if ((*cp != '\0') && (__inet_pton (AF_INET6, cp, &a6) > 0)) @@ -472,7 +477,7 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) char separator = *cp; *cp = 0; struct resolv_sortlist_entry e; - if (__inet_aton (net, &a)) + if (__inet_aton_exact (net, &a)) { e.addr = a; if (is_sort_mask (separator)) @@ -484,7 +489,7 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) cp++; separator = *cp; *cp = 0; - if (__inet_aton (net, &a)) + if (__inet_aton_exact (net, &a)) e.mask = a.s_addr; else e.mask = net_mask (e.addr); diff --git a/resolv/tst-aton.c b/resolv/tst-aton.c index 08110a007a..eb734d7758 100644 --- a/resolv/tst-aton.c +++ b/resolv/tst-aton.c @@ -1,11 +1,29 @@ +/* Test legacy IPv4 text-to-address function inet_aton. + Copyright (C) 1998-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <array_length.h> #include <stdio.h> #include <stdint.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> - -static struct tests +static const struct tests { const char *input; int valid; @@ -16,6 +34,7 @@ static struct tests { "-1", 0, 0 }, { "256", 1, 0x00000100 }, { "256.", 0, 0 }, + { "255a", 0, 0 }, { "256a", 0, 0 }, { "0x100", 1, 0x00000100 }, { "0200.0x123456", 1, 0x80123456 }, @@ -40,7 +59,12 @@ static struct tests { "1.2.256.4", 0, 0 }, { "1.2.3.0x100", 0, 0 }, { "323543357756889", 0, 0 }, - { "10.1.2.3.4", 0, 0}, + { "10.1.2.3.4", 0, 0 }, + { "192.0.2.1", 1, 0xc0000201 }, + { "192.0.2.2\nX", 1, 0xc0000202 }, + { "192.0.2.3 Y", 1, 0xc0000203 }, + { "192.0.2.3Z", 0, 0 }, + { "192.000.002.010", 1, 0xc0000208 }, }; @@ -50,7 +74,7 @@ do_test (void) int result = 0; size_t cnt; - for (cnt = 0; cnt < sizeof (tests) / sizeof (tests[0]); ++cnt) + for (cnt = 0; cnt < array_length (tests); ++cnt) { struct in_addr addr; @@ -73,5 +97,4 @@ do_test (void) return result; } -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include <support/test-driver.c> diff --git a/resolv/tst-inet_aton_exact.c b/resolv/tst-inet_aton_exact.c new file mode 100644 index 0000000000..0fdfa3d6aa --- /dev/null +++ b/resolv/tst-inet_aton_exact.c @@ -0,0 +1,47 @@ +/* Test internal legacy IPv4 text-to-address function __inet_aton_exact. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <arpa/inet.h> +#include <support/check.h> + +static int +do_test (void) +{ + struct in_addr addr = { }; + + TEST_COMPARE (__inet_aton_exact ("192.0.2.1", &addr), 1); + TEST_COMPARE (ntohl (addr.s_addr), 0xC0000201); + + TEST_COMPARE (__inet_aton_exact ("192.000.002.010", &addr), 1); + TEST_COMPARE (ntohl (addr.s_addr), 0xC0000208); + TEST_COMPARE (__inet_aton_exact ("0xC0000234", &addr), 1); + TEST_COMPARE (ntohl (addr.s_addr), 0xC0000234); + + /* Trailing content is not accepted. */ + TEST_COMPARE (__inet_aton_exact ("192.0.2.2X", &addr), 0); + TEST_COMPARE (__inet_aton_exact ("192.0.2.3 Y", &addr), 0); + TEST_COMPARE (__inet_aton_exact ("192.0.2.4\nZ", &addr), 0); + TEST_COMPARE (__inet_aton_exact ("192.0.2.5\tT", &addr), 0); + TEST_COMPARE (__inet_aton_exact ("192.0.2.6 Y", &addr), 0); + TEST_COMPARE (__inet_aton_exact ("192.0.2.7\n", &addr), 0); + TEST_COMPARE (__inet_aton_exact ("192.0.2.8\t", &addr), 0); + + return 0; +} + +#include <support/test-driver.c> diff --git a/resolv/tst-resolv-nondecimal.c b/resolv/tst-resolv-nondecimal.c new file mode 100644 index 0000000000..a0df6f332a --- /dev/null +++ b/resolv/tst-resolv-nondecimal.c @@ -0,0 +1,139 @@ +/* Test name resolution behavior for octal, hexadecimal IPv4 addresses. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <netdb.h> +#include <stdlib.h> +#include <support/check.h> +#include <support/check_nss.h> +#include <support/resolv_test.h> +#include <support/support.h> + +static void +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + /* The tests are not supposed send any DNS queries. */ + FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype); +} + +static void +run_query_addrinfo (const char *query, const char *address) +{ + char *quoted_query = support_quote_string (query); + + struct addrinfo *ai; + struct addrinfo hints = + { + .ai_socktype = SOCK_STREAM, + .ai_protocol = IPPROTO_TCP, + }; + + char *context = xasprintf ("getaddrinfo \"%s\" AF_INET", quoted_query); + char *expected = xasprintf ("address: STREAM/TCP %s 80\n", address); + hints.ai_family = AF_INET; + int ret = getaddrinfo (query, "80", &hints, &ai); + check_addrinfo (context, ai, ret, expected); + if (ret == 0) + freeaddrinfo (ai); + free (context); + + context = xasprintf ("getaddrinfo \"%s\" AF_UNSPEC", quoted_query); + hints.ai_family = AF_UNSPEC; + ret = getaddrinfo (query, "80", &hints, &ai); + check_addrinfo (context, ai, ret, expected); + if (ret == 0) + freeaddrinfo (ai); + free (expected); + free (context); + + context = xasprintf ("getaddrinfo \"%s\" AF_INET6", quoted_query); + expected = xasprintf ("flags: AI_V4MAPPED\n" + "address: STREAM/TCP ::ffff:%s 80\n", + address); + hints.ai_family = AF_INET6; + hints.ai_flags = AI_V4MAPPED; + ret = getaddrinfo (query, "80", &hints, &ai); + check_addrinfo (context, ai, ret, expected); + if (ret == 0) + freeaddrinfo (ai); + free (expected); + free (context); + + free (quoted_query); +} + +static void +run_query (const char *query, const char *address) +{ + char *quoted_query = support_quote_string (query); + char *context = xasprintf ("gethostbyname (\"%s\")", quoted_query); + char *expected = xasprintf ("name: %s\n" + "address: %s\n", query, address); + check_hostent (context, gethostbyname (query), expected); + free (context); + + context = xasprintf ("gethostbyname_r \"%s\"", quoted_query); + struct hostent storage; + char buf[4096]; + struct hostent *e = NULL; + TEST_COMPARE (gethostbyname_r (query, &storage, buf, sizeof (buf), + &e, &h_errno), 0); + check_hostent (context, e, expected); + free (context); + + context = xasprintf ("gethostbyname2 (\"%s\", AF_INET)", quoted_query); + check_hostent (context, gethostbyname2 (query, AF_INET), expected); + free (context); + + context = xasprintf ("gethostbyname2_r \"%s\" AF_INET", quoted_query); + e = NULL; + TEST_COMPARE (gethostbyname2_r (query, AF_INET, &storage, buf, sizeof (buf), + &e, &h_errno), 0); + check_hostent (context, e, expected); + free (context); + free (expected); + + free (quoted_query); + + /* The gethostbyname tests are always valid for getaddrinfo, but not + vice versa. */ + run_query_addrinfo (query, address); +} + +static int +do_test (void) +{ + struct resolv_test *aux = resolv_test_start + ((struct resolv_redirect_config) + { + .response_callback = response, + }); + + run_query ("192.000.002.010", "192.0.2.8"); + + /* Hexadecimal numbers are not accepted by gethostbyname. */ + run_query_addrinfo ("0xc0000210", "192.0.2.16"); + run_query_addrinfo ("192.0x234", "192.0.2.52"); + + resolv_test_end (aux); + + return 0; +} + +#include <support/test-driver.c> diff --git a/resolv/tst-resolv-trailing.c b/resolv/tst-resolv-trailing.c new file mode 100644 index 0000000000..7504bdae57 --- /dev/null +++ b/resolv/tst-resolv-trailing.c @@ -0,0 +1,136 @@ +/* Test name resolution behavior with trailing characters. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <array_length.h> +#include <netdb.h> +#include <support/check.h> +#include <support/check_nss.h> +#include <support/resolv_test.h> +#include <support/support.h> + +static void +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + /* The tests are not supposed send any DNS queries. */ + FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype); +} + +static int +do_test (void) +{ + struct resolv_test *aux = resolv_test_start + ((struct resolv_redirect_config) + { + .response_callback = response, + }); + + static const char *const queries[] = + { + "192.0.2.1 ", + "192.0.2.2\t", + "192.0.2.3\n", + "192.0.2.4 X", + "192.0.2.5\tY", + "192.0.2.6\nZ", + "192.0.2. ", + "192.0.2.\t", + "192.0.2.\n", + "192.0.2. X", + "192.0.2.\tY", + "192.0.2.\nZ", + "2001:db8::1 ", + "2001:db8::2\t", + "2001:db8::3\n", + "2001:db8::4 X", + "2001:db8::5\tY", + "2001:db8::6\nZ", + }; + for (size_t query_idx = 0; query_idx < array_length (queries); ++query_idx) + { + const char *query = queries[query_idx]; + struct hostent storage; + char buf[4096]; + struct hostent *e; + + h_errno = 0; + TEST_VERIFY (gethostbyname (query) == NULL); + TEST_COMPARE (h_errno, HOST_NOT_FOUND); + + h_errno = 0; + e = NULL; + TEST_COMPARE (gethostbyname_r (query, &storage, buf, sizeof (buf), + &e, &h_errno), 0); + TEST_VERIFY (e == NULL); + TEST_COMPARE (h_errno, HOST_NOT_FOUND); + + h_errno = 0; + TEST_VERIFY (gethostbyname2 (query, AF_INET) == NULL); + TEST_COMPARE (h_errno, HOST_NOT_FOUND); + + h_errno = 0; + e = NULL; + TEST_COMPARE (gethostbyname2_r (query, AF_INET, + &storage, buf, sizeof (buf), + &e, &h_errno), 0); + TEST_VERIFY (e == NULL); + TEST_COMPARE (h_errno, HOST_NOT_FOUND); + + h_errno = 0; + TEST_VERIFY (gethostbyname2 (query, AF_INET6) == NULL); + TEST_COMPARE (h_errno, HOST_NOT_FOUND); + + h_errno = 0; + e = NULL; + TEST_COMPARE (gethostbyname2_r (query, AF_INET6, + &storage, buf, sizeof (buf), + &e, &h_errno), 0); + TEST_VERIFY (e == NULL); + TEST_COMPARE (h_errno, HOST_NOT_FOUND); + + static const int gai_flags[] = + { + 0, + AI_ADDRCONFIG, + AI_NUMERICHOST, + AI_IDN, + AI_IDN | AI_NUMERICHOST, + AI_V4MAPPED, + AI_V4MAPPED | AI_NUMERICHOST, + }; + for (size_t gai_flags_idx; gai_flags_idx < array_length (gai_flags); + ++gai_flags_idx) + { + struct addrinfo hints = { .ai_flags = gai_flags[gai_flags_idx], }; + struct addrinfo *ai; + hints.ai_family = AF_INET; + TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME); + hints.ai_family = AF_INET6; + TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME); + hints.ai_family = AF_UNSPEC; + TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME); + } + }; + + resolv_test_end (aux); + + return 0; +} + +#include <support/test-driver.c> |