commit 228cdb00a045ae3b68a91b35c7548bab6029446e Author: Siddhesh Poyarekar Date: Thu Mar 17 11:44:34 2022 +0530 Simplify allocations and fix merge and continue actions [BZ #28931] Allocations for address tuples is currently a bit confusing because of the pointer chasing through PAT, making it hard to observe the sequence in which allocations have been made. Narrow scope of the pointer chasing through PAT so that it is only used where necessary. This also tightens actions behaviour with the hosts database in getaddrinfo to comply with the manual text. The "continue" action discards previous results and the "merge" action results in an immedate lookup failure. Consequently, chaining of allocations across modules is no longer necessary, thus opening up cleanup opportunities. A test has been added that checks some combinations to ensure that they work correctly. Resolves: BZ #28931 Signed-off-by: Siddhesh Poyarekar Reviewed-by: DJ Delorie (cherry picked from commit 1c37b8022e8763fedbb3f79c02e05c6acfe5a215) Conflicts: nss/Makefile (Missing test cases) sysdeps/posix/getaddrinfo.c (RES_USE_INET6 still present in RHEL-8 and NSS module traversal rewrite not in RHEL-8) diff --git a/nss/Makefile b/nss/Makefile index e8a7d9c7b3cefcdf..cfb255c6e7a3a4de 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -65,7 +65,8 @@ xtests = bug-erange tests-container = \ tst-nss-db-endpwent \ - tst-nss-db-endgrent + tst-nss-db-endgrent \ + tst-nss-gai-actions # Tests which need libdl ifeq (yes,$(build-shared)) diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c new file mode 100644 index 0000000000000000..efca6cd1837a172a --- /dev/null +++ b/nss/tst-nss-gai-actions.c @@ -0,0 +1,149 @@ +/* Test continue and merge NSS actions for getaddrinfo. + Copyright The GNU Toolchain Authors. + 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 + . */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +enum +{ + ACTION_MERGE = 0, + ACTION_CONTINUE, +}; + +static const char * +family_str (int family) +{ + switch (family) + { + case AF_UNSPEC: + return "AF_UNSPEC"; + case AF_INET: + return "AF_INET"; + default: + __builtin_unreachable (); + } +} + +static const char * +action_str (int action) +{ + switch (action) + { + case ACTION_MERGE: + return "merge"; + case ACTION_CONTINUE: + return "continue"; + default: + __builtin_unreachable (); + } +} + +static void +do_one_test (int action, int family, bool canon) +{ + struct addrinfo hints = + { + .ai_family = family, + }; + + struct addrinfo *ai; + + if (canon) + hints.ai_flags = AI_CANONNAME; + + printf ("***** Testing \"files [SUCCESS=%s] files\" for family %s, %s\n", + action_str (action), family_str (family), + canon ? "AI_CANONNAME" : ""); + + int ret = getaddrinfo ("example.org", "80", &hints, &ai); + + switch (action) + { + case ACTION_MERGE: + if (ret == 0) + { + char *formatted = support_format_addrinfo (ai, ret); + + printf ("merge unexpectedly succeeded:\n %s\n", formatted); + support_record_failure (); + free (formatted); + } + else + return; + case ACTION_CONTINUE: + { + char *formatted = support_format_addrinfo (ai, ret); + + /* Verify that the result appears exactly once. */ + const char *expected = "address: STREAM/TCP 192.0.0.1 80\n" + "address: DGRAM/UDP 192.0.0.1 80\n" + "address: RAW/IP 192.0.0.1 80\n"; + + const char *contains = strstr (formatted, expected); + const char *contains2 = NULL; + + if (contains != NULL) + contains2 = strstr (contains + strlen (expected), expected); + + if (contains == NULL || contains2 != NULL) + { + printf ("continue failed:\n%s\n", formatted); + support_record_failure (); + } + + free (formatted); + break; + } + default: + __builtin_unreachable (); + } +} + +static void +do_one_test_set (int action) +{ + char buf[32]; + + snprintf (buf, sizeof (buf), "files [SUCCESS=%s] files", + action_str (action)); + __nss_configure_lookup ("hosts", buf); + + do_one_test (action, AF_UNSPEC, false); + do_one_test (action, AF_INET, false); + do_one_test (action, AF_INET, true); +} + +static int +do_test (void) +{ + do_one_test_set (ACTION_CONTINUE); + do_one_test_set (ACTION_MERGE); + return 0; +} + +#include diff --git a/nss/tst-nss-gai-actions.root/etc/host.conf b/nss/tst-nss-gai-actions.root/etc/host.conf new file mode 100644 index 0000000000000000..d1a59f73a90f2993 --- /dev/null +++ b/nss/tst-nss-gai-actions.root/etc/host.conf @@ -0,0 +1 @@ +multi on diff --git a/nss/tst-nss-gai-actions.root/etc/hosts b/nss/tst-nss-gai-actions.root/etc/hosts new file mode 100644 index 0000000000000000..50ce9774dc2c21d9 --- /dev/null +++ b/nss/tst-nss-gai-actions.root/etc/hosts @@ -0,0 +1,508 @@ +192.0.0.1 example.org +192.0.0.2 example.org +192.0.0.3 example.org +192.0.0.4 example.org +192.0.0.5 example.org +192.0.0.6 example.org +192.0.0.7 example.org +192.0.0.8 example.org +192.0.0.9 example.org +192.0.0.10 example.org +192.0.0.11 example.org +192.0.0.12 example.org +192.0.0.13 example.org +192.0.0.14 example.org +192.0.0.15 example.org +192.0.0.16 example.org +192.0.0.17 example.org +192.0.0.18 example.org +192.0.0.19 example.org +192.0.0.20 example.org +192.0.0.21 example.org +192.0.0.22 example.org +192.0.0.23 example.org +192.0.0.24 example.org +192.0.0.25 example.org +192.0.0.26 example.org +192.0.0.27 example.org +192.0.0.28 example.org +192.0.0.29 example.org +192.0.0.30 example.org +192.0.0.31 example.org +192.0.0.32 example.org +192.0.0.33 example.org +192.0.0.34 example.org +192.0.0.35 example.org +192.0.0.36 example.org +192.0.0.37 example.org +192.0.0.38 example.org +192.0.0.39 example.org +192.0.0.40 example.org +192.0.0.41 example.org +192.0.0.42 example.org +192.0.0.43 example.org +192.0.0.44 example.org +192.0.0.45 example.org +192.0.0.46 example.org +192.0.0.47 example.org +192.0.0.48 example.org +192.0.0.49 example.org +192.0.0.50 example.org +192.0.0.51 example.org +192.0.0.52 example.org +192.0.0.53 example.org +192.0.0.54 example.org +192.0.0.55 example.org +192.0.0.56 example.org +192.0.0.57 example.org +192.0.0.58 example.org +192.0.0.59 example.org +192.0.0.60 example.org +192.0.0.61 example.org +192.0.0.62 example.org +192.0.0.63 example.org +192.0.0.64 example.org +192.0.0.65 example.org +192.0.0.66 example.org +192.0.0.67 example.org +192.0.0.68 example.org +192.0.0.69 example.org +192.0.0.70 example.org +192.0.0.71 example.org +192.0.0.72 example.org +192.0.0.73 example.org +192.0.0.74 example.org +192.0.0.75 example.org +192.0.0.76 example.org +192.0.0.77 example.org +192.0.0.78 example.org +192.0.0.79 example.org +192.0.0.80 example.org +192.0.0.81 example.org +192.0.0.82 example.org +192.0.0.83 example.org +192.0.0.84 example.org +192.0.0.85 example.org +192.0.0.86 example.org +192.0.0.87 example.org +192.0.0.88 example.org +192.0.0.89 example.org +192.0.0.90 example.org +192.0.0.91 example.org +192.0.0.92 example.org +192.0.0.93 example.org +192.0.0.94 example.org +192.0.0.95 example.org +192.0.0.96 example.org +192.0.0.97 example.org +192.0.0.98 example.org +192.0.0.99 example.org +192.0.0.100 example.org +192.0.0.101 example.org +192.0.0.102 example.org +192.0.0.103 example.org +192.0.0.104 example.org +192.0.0.105 example.org +192.0.0.106 example.org +192.0.0.107 example.org +192.0.0.108 example.org +192.0.0.109 example.org +192.0.0.110 example.org +192.0.0.111 example.org +192.0.0.112 example.org +192.0.0.113 example.org +192.0.0.114 example.org +192.0.0.115 example.org +192.0.0.116 example.org +192.0.0.117 example.org +192.0.0.118 example.org +192.0.0.119 example.org +192.0.0.120 example.org +192.0.0.121 example.org +192.0.0.122 example.org +192.0.0.123 example.org +192.0.0.124 example.org +192.0.0.125 example.org +192.0.0.126 example.org +192.0.0.127 example.org +192.0.0.128 example.org +192.0.0.129 example.org +192.0.0.130 example.org +192.0.0.131 example.org +192.0.0.132 example.org +192.0.0.133 example.org +192.0.0.134 example.org +192.0.0.135 example.org +192.0.0.136 example.org +192.0.0.137 example.org +192.0.0.138 example.org +192.0.0.139 example.org +192.0.0.140 example.org +192.0.0.141 example.org +192.0.0.142 example.org +192.0.0.143 example.org +192.0.0.144 example.org +192.0.0.145 example.org +192.0.0.146 example.org +192.0.0.147 example.org +192.0.0.148 example.org +192.0.0.149 example.org +192.0.0.150 example.org +192.0.0.151 example.org +192.0.0.152 example.org +192.0.0.153 example.org +192.0.0.154 example.org +192.0.0.155 example.org +192.0.0.156 example.org +192.0.0.157 example.org +192.0.0.158 example.org +192.0.0.159 example.org +192.0.0.160 example.org +192.0.0.161 example.org +192.0.0.162 example.org +192.0.0.163 example.org +192.0.0.164 example.org +192.0.0.165 example.org +192.0.0.166 example.org +192.0.0.167 example.org +192.0.0.168 example.org +192.0.0.169 example.org +192.0.0.170 example.org +192.0.0.171 example.org +192.0.0.172 example.org +192.0.0.173 example.org +192.0.0.174 example.org +192.0.0.175 example.org +192.0.0.176 example.org +192.0.0.177 example.org +192.0.0.178 example.org +192.0.0.179 example.org +192.0.0.180 example.org +192.0.0.181 example.org +192.0.0.182 example.org +192.0.0.183 example.org +192.0.0.184 example.org +192.0.0.185 example.org +192.0.0.186 example.org +192.0.0.187 example.org +192.0.0.188 example.org +192.0.0.189 example.org +192.0.0.190 example.org +192.0.0.191 example.org +192.0.0.192 example.org +192.0.0.193 example.org +192.0.0.194 example.org +192.0.0.195 example.org +192.0.0.196 example.org +192.0.0.197 example.org +192.0.0.198 example.org +192.0.0.199 example.org +192.0.0.200 example.org +192.0.0.201 example.org +192.0.0.202 example.org +192.0.0.203 example.org +192.0.0.204 example.org +192.0.0.205 example.org +192.0.0.206 example.org +192.0.0.207 example.org +192.0.0.208 example.org +192.0.0.209 example.org +192.0.0.210 example.org +192.0.0.211 example.org +192.0.0.212 example.org +192.0.0.213 example.org +192.0.0.214 example.org +192.0.0.215 example.org +192.0.0.216 example.org +192.0.0.217 example.org +192.0.0.218 example.org +192.0.0.219 example.org +192.0.0.220 example.org +192.0.0.221 example.org +192.0.0.222 example.org +192.0.0.223 example.org +192.0.0.224 example.org +192.0.0.225 example.org +192.0.0.226 example.org +192.0.0.227 example.org +192.0.0.228 example.org +192.0.0.229 example.org +192.0.0.230 example.org +192.0.0.231 example.org +192.0.0.232 example.org +192.0.0.233 example.org +192.0.0.234 example.org +192.0.0.235 example.org +192.0.0.236 example.org +192.0.0.237 example.org +192.0.0.238 example.org +192.0.0.239 example.org +192.0.0.240 example.org +192.0.0.241 example.org +192.0.0.242 example.org +192.0.0.243 example.org +192.0.0.244 example.org +192.0.0.245 example.org +192.0.0.246 example.org +192.0.0.247 example.org +192.0.0.248 example.org +192.0.0.249 example.org +192.0.0.250 example.org +192.0.0.251 example.org +192.0.0.252 example.org +192.0.0.253 example.org +192.0.0.254 example.org +192.0.1.1 example.org +192.0.1.2 example.org +192.0.1.3 example.org +192.0.1.4 example.org +192.0.1.5 example.org +192.0.1.6 example.org +192.0.1.7 example.org +192.0.1.8 example.org +192.0.1.9 example.org +192.0.1.10 example.org +192.0.1.11 example.org +192.0.1.12 example.org +192.0.1.13 example.org +192.0.1.14 example.org +192.0.1.15 example.org +192.0.1.16 example.org +192.0.1.17 example.org +192.0.1.18 example.org +192.0.1.19 example.org +192.0.1.20 example.org +192.0.1.21 example.org +192.0.1.22 example.org +192.0.1.23 example.org +192.0.1.24 example.org +192.0.1.25 example.org +192.0.1.26 example.org +192.0.1.27 example.org +192.0.1.28 example.org +192.0.1.29 example.org +192.0.1.30 example.org +192.0.1.31 example.org +192.0.1.32 example.org +192.0.1.33 example.org +192.0.1.34 example.org +192.0.1.35 example.org +192.0.1.36 example.org +192.0.1.37 example.org +192.0.1.38 example.org +192.0.1.39 example.org +192.0.1.40 example.org +192.0.1.41 example.org +192.0.1.42 example.org +192.0.1.43 example.org +192.0.1.44 example.org +192.0.1.45 example.org +192.0.1.46 example.org +192.0.1.47 example.org +192.0.1.48 example.org +192.0.1.49 example.org +192.0.1.50 example.org +192.0.1.51 example.org +192.0.1.52 example.org +192.0.1.53 example.org +192.0.1.54 example.org +192.0.1.55 example.org +192.0.1.56 example.org +192.0.1.57 example.org +192.0.1.58 example.org +192.0.1.59 example.org +192.0.1.60 example.org +192.0.1.61 example.org +192.0.1.62 example.org +192.0.1.63 example.org +192.0.1.64 example.org +192.0.1.65 example.org +192.0.1.66 example.org +192.0.1.67 example.org +192.0.1.68 example.org +192.0.1.69 example.org +192.0.1.70 example.org +192.0.1.71 example.org +192.0.1.72 example.org +192.0.1.73 example.org +192.0.1.74 example.org +192.0.1.75 example.org +192.0.1.76 example.org +192.0.1.77 example.org +192.0.1.78 example.org +192.0.1.79 example.org +192.0.1.80 example.org +192.0.1.81 example.org +192.0.1.82 example.org +192.0.1.83 example.org +192.0.1.84 example.org +192.0.1.85 example.org +192.0.1.86 example.org +192.0.1.87 example.org +192.0.1.88 example.org +192.0.1.89 example.org +192.0.1.90 example.org +192.0.1.91 example.org +192.0.1.92 example.org +192.0.1.93 example.org +192.0.1.94 example.org +192.0.1.95 example.org +192.0.1.96 example.org +192.0.1.97 example.org +192.0.1.98 example.org +192.0.1.99 example.org +192.0.1.100 example.org +192.0.1.101 example.org +192.0.1.102 example.org +192.0.1.103 example.org +192.0.1.104 example.org +192.0.1.105 example.org +192.0.1.106 example.org +192.0.1.107 example.org +192.0.1.108 example.org +192.0.1.109 example.org +192.0.1.110 example.org +192.0.1.111 example.org +192.0.1.112 example.org +192.0.1.113 example.org +192.0.1.114 example.org +192.0.1.115 example.org +192.0.1.116 example.org +192.0.1.117 example.org +192.0.1.118 example.org +192.0.1.119 example.org +192.0.1.120 example.org +192.0.1.121 example.org +192.0.1.122 example.org +192.0.1.123 example.org +192.0.1.124 example.org +192.0.1.125 example.org +192.0.1.126 example.org +192.0.1.127 example.org +192.0.1.128 example.org +192.0.1.129 example.org +192.0.1.130 example.org +192.0.1.131 example.org +192.0.1.132 example.org +192.0.1.133 example.org +192.0.1.134 example.org +192.0.1.135 example.org +192.0.1.136 example.org +192.0.1.137 example.org +192.0.1.138 example.org +192.0.1.139 example.org +192.0.1.140 example.org +192.0.1.141 example.org +192.0.1.142 example.org +192.0.1.143 example.org +192.0.1.144 example.org +192.0.1.145 example.org +192.0.1.146 example.org +192.0.1.147 example.org +192.0.1.148 example.org +192.0.1.149 example.org +192.0.1.150 example.org +192.0.1.151 example.org +192.0.1.152 example.org +192.0.1.153 example.org +192.0.1.154 example.org +192.0.1.155 example.org +192.0.1.156 example.org +192.0.1.157 example.org +192.0.1.158 example.org +192.0.1.159 example.org +192.0.1.160 example.org +192.0.1.161 example.org +192.0.1.162 example.org +192.0.1.163 example.org +192.0.1.164 example.org +192.0.1.165 example.org +192.0.1.166 example.org +192.0.1.167 example.org +192.0.1.168 example.org +192.0.1.169 example.org +192.0.1.170 example.org +192.0.1.171 example.org +192.0.1.172 example.org +192.0.1.173 example.org +192.0.1.174 example.org +192.0.1.175 example.org +192.0.1.176 example.org +192.0.1.177 example.org +192.0.1.178 example.org +192.0.1.179 example.org +192.0.1.180 example.org +192.0.1.181 example.org +192.0.1.182 example.org +192.0.1.183 example.org +192.0.1.184 example.org +192.0.1.185 example.org +192.0.1.186 example.org +192.0.1.187 example.org +192.0.1.188 example.org +192.0.1.189 example.org +192.0.1.190 example.org +192.0.1.191 example.org +192.0.1.192 example.org +192.0.1.193 example.org +192.0.1.194 example.org +192.0.1.195 example.org +192.0.1.196 example.org +192.0.1.197 example.org +192.0.1.198 example.org +192.0.1.199 example.org +192.0.1.200 example.org +192.0.1.201 example.org +192.0.1.202 example.org +192.0.1.203 example.org +192.0.1.204 example.org +192.0.1.205 example.org +192.0.1.206 example.org +192.0.1.207 example.org +192.0.1.208 example.org +192.0.1.209 example.org +192.0.1.210 example.org +192.0.1.211 example.org +192.0.1.212 example.org +192.0.1.213 example.org +192.0.1.214 example.org +192.0.1.215 example.org +192.0.1.216 example.org +192.0.1.217 example.org +192.0.1.218 example.org +192.0.1.219 example.org +192.0.1.220 example.org +192.0.1.221 example.org +192.0.1.222 example.org +192.0.1.223 example.org +192.0.1.224 example.org +192.0.1.225 example.org +192.0.1.226 example.org +192.0.1.227 example.org +192.0.1.228 example.org +192.0.1.229 example.org +192.0.1.230 example.org +192.0.1.231 example.org +192.0.1.232 example.org +192.0.1.233 example.org +192.0.1.234 example.org +192.0.1.235 example.org +192.0.1.236 example.org +192.0.1.237 example.org +192.0.1.238 example.org +192.0.1.239 example.org +192.0.1.240 example.org +192.0.1.241 example.org +192.0.1.242 example.org +192.0.1.243 example.org +192.0.1.244 example.org +192.0.1.245 example.org +192.0.1.246 example.org +192.0.1.247 example.org +192.0.1.248 example.org +192.0.1.249 example.org +192.0.1.250 example.org +192.0.1.251 example.org +192.0.1.252 example.org +192.0.1.253 example.org +192.0.1.254 example.org diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index fae3dea81f19dba6..4fa963644af8b7d5 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -474,11 +474,6 @@ gaih_inet (const char *name, const struct gaih_service *service, if (name != NULL) { - at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used); - at->family = AF_UNSPEC; - at->scopeid = 0; - at->next = NULL; - if (req->ai_flags & AI_IDN) { char *out; @@ -489,13 +484,21 @@ gaih_inet (const char *name, const struct gaih_service *service, malloc_name = true; } - if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0) + uint32_t addr[4]; + if (__inet_aton_exact (name, (struct in_addr *) addr) != 0) { + at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used); + at->scopeid = 0; + at->next = NULL; + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) - at->family = AF_INET; + { + memcpy (at->addr, addr, sizeof (at->addr)); + at->family = AF_INET; + } else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED)) { - at->addr[3] = at->addr[0]; + at->addr[3] = addr[0]; at->addr[2] = htonl (0xffff); at->addr[1] = 0; at->addr[0] = 0; @@ -509,49 +512,62 @@ gaih_inet (const char *name, const struct gaih_service *service, if (req->ai_flags & AI_CANONNAME) canon = name; + + goto process_list; } - else if (at->family == AF_UNSPEC) + + char *scope_delim = strchr (name, SCOPE_DELIMITER); + int e; + + if (scope_delim == NULL) + e = inet_pton (AF_INET6, name, addr); + else + e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr); + + if (e > 0) { - char *scope_delim = strchr (name, SCOPE_DELIMITER); - int e; - if (scope_delim == NULL) - e = inet_pton (AF_INET6, name, at->addr); + at = alloca_account (sizeof (struct gaih_addrtuple), + alloca_used); + at->scopeid = 0; + at->next = NULL; + + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) + { + memcpy (at->addr, addr, sizeof (at->addr)); + at->family = AF_INET6; + } + else if (req->ai_family == AF_INET + && IN6_IS_ADDR_V4MAPPED (addr)) + { + at->addr[0] = addr[3]; + at->addr[1] = addr[1]; + at->addr[2] = addr[2]; + at->addr[3] = addr[3]; + at->family = AF_INET; + } else - e = __inet_pton_length (AF_INET6, name, scope_delim - name, - at->addr); - if (e > 0) { - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) - at->family = AF_INET6; - else if (req->ai_family == AF_INET - && IN6_IS_ADDR_V4MAPPED (at->addr)) - { - at->addr[0] = at->addr[3]; - at->family = AF_INET; - } - else - { - result = -EAI_ADDRFAMILY; - goto free_and_return; - } - - if (scope_delim != NULL - && __inet6_scopeid_pton ((struct in6_addr *) at->addr, - scope_delim + 1, - &at->scopeid) != 0) - { - result = -EAI_NONAME; - goto free_and_return; - } + result = -EAI_ADDRFAMILY; + goto free_and_return; + } - if (req->ai_flags & AI_CANONNAME) - canon = name; + if (scope_delim != NULL + && __inet6_scopeid_pton ((struct in6_addr *) at->addr, + scope_delim + 1, + &at->scopeid) != 0) + { + result = -EAI_NONAME; + goto free_and_return; } + + if (req->ai_flags & AI_CANONNAME) + canon = name; + + goto process_list; } - if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0) + if ((req->ai_flags & AI_NUMERICHOST) == 0) { - struct gaih_addrtuple **pat = &at; int no_data = 0; int no_inet6_data = 0; service_user *nip; @@ -560,6 +576,7 @@ gaih_inet (const char *name, const struct gaih_service *service, int no_more; struct resolv_context *res_ctx = NULL; bool res_enable_inet6 = false; + bool do_merge = false; /* If we do not have to look for IPv6 addresses or the canonical name, use the simple, old functions, which do not support @@ -596,7 +613,7 @@ gaih_inet (const char *name, const struct gaih_service *service, result = -EAI_MEMORY; goto free_and_return; } - *pat = addrmem; + at = addrmem; } else { @@ -649,6 +666,8 @@ gaih_inet (const char *name, const struct gaih_service *service, } struct gaih_addrtuple *addrfree = addrmem; + struct gaih_addrtuple **pat = &at; + for (int i = 0; i < air->naddrs; ++i) { socklen_t size = (air->family[i] == AF_INET @@ -712,12 +731,6 @@ gaih_inet (const char *name, const struct gaih_service *service, free (air); - if (at->family == AF_UNSPEC) - { - result = -EAI_NONAME; - goto free_and_return; - } - goto process_list; } else if (err == 0) @@ -756,6 +769,22 @@ gaih_inet (const char *name, const struct gaih_service *service, while (!no_more) { + /* Always start afresh; continue should discard previous results + and the hosts database does not support merge. */ + at = NULL; + free (canonbuf); + free (addrmem); + canon = canonbuf = NULL; + addrmem = NULL; + got_ipv6 = false; + + if (do_merge) + { + __set_h_errno (NETDB_INTERNAL); + __set_errno (EBUSY); + break; + } + no_data = 0; nss_gethostbyname4_r fct4 = NULL; @@ -768,12 +797,14 @@ gaih_inet (const char *name, const struct gaih_service *service, { while (1) { - status = DL_CALL_FCT (fct4, (name, pat, + status = DL_CALL_FCT (fct4, (name, &at, tmpbuf->data, tmpbuf->length, &errno, &h_errno, NULL)); if (status == NSS_STATUS_SUCCESS) break; + /* gethostbyname4_r may write into AT, so reset it. */ + at = NULL; if (status != NSS_STATUS_TRYAGAIN || errno != ERANGE || h_errno != NETDB_INTERNAL) { @@ -800,7 +831,9 @@ gaih_inet (const char *name, const struct gaih_service *service, no_data = 1; if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL) - canon = (*pat)->name; + canon = at->name; + + struct gaih_addrtuple **pat = &at; while (*pat != NULL) { @@ -852,6 +885,8 @@ gaih_inet (const char *name, const struct gaih_service *service, if (fct != NULL) { + struct gaih_addrtuple **pat = &at; + if (req->ai_family == AF_INET6 || req->ai_family == AF_UNSPEC) { @@ -927,6 +962,10 @@ gaih_inet (const char *name, const struct gaih_service *service, if (nss_next_action (nip, status) == NSS_ACTION_RETURN) break; + /* The hosts database does not support MERGE. */ + if (nss_next_action (nip, status) == NSS_ACTION_MERGE) + do_merge = true; + if (nip->next == NULL) no_more = -1; else @@ -960,7 +999,7 @@ gaih_inet (const char *name, const struct gaih_service *service, } process_list: - if (at->family == AF_UNSPEC) + if (at == NULL) { result = -EAI_NONAME; goto free_and_return;