]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
6b21f0cf | 2 | |
6b21f0cf | 3 | #include <errno.h> |
4e8c8252 | 4 | #include <net/if.h> |
07630cea LP |
5 | #include <netdb.h> |
6 | #include <nss.h> | |
8041b5ba | 7 | #include <stdlib.h> |
8041b5ba | 8 | |
b5efdb8a | 9 | #include "alloc-util.h" |
2b2fec7d | 10 | #include "errno-util.h" |
07630cea | 11 | #include "hostname-util.h" |
e80af1bd | 12 | #include "local-addresses.h" |
1c633045 | 13 | #include "macro.h" |
c9fdc26e | 14 | #include "nss-util.h" |
056c398b | 15 | #include "resolve-util.h" |
0c5eb056 | 16 | #include "signal-util.h" |
db50d326 | 17 | #include "socket-util.h" |
07630cea | 18 | #include "string-util.h" |
4e8c8252 LP |
19 | |
20 | /* We use 127.0.0.2 as IPv4 address. This has the advantage over | |
21 | * 127.0.0.1 that it can be translated back to the local hostname. For | |
22 | * IPv6 we use ::1 which unfortunately will not translate back to the | |
3fdcecc8 | 23 | * hostname but instead something like "localhost" or so. */ |
4e8c8252 | 24 | |
056c398b | 25 | #define LOCALADDRESS_IPV4 (htobe32(INADDR_LOCALADDRESS)) |
4e8c8252 | 26 | #define LOCALADDRESS_IPV6 &in6addr_loopback |
4e8c8252 | 27 | |
c9fdc26e LP |
28 | NSS_GETHOSTBYNAME_PROTOTYPES(myhostname); |
29 | NSS_GETHOSTBYADDR_PROTOTYPES(myhostname); | |
8041b5ba | 30 | |
4e8c8252 LP |
31 | enum nss_status _nss_myhostname_gethostbyname4_r( |
32 | const char *name, | |
33 | struct gaih_addrtuple **pat, | |
34 | char *buffer, size_t buflen, | |
35 | int *errnop, int *h_errnop, | |
36 | int32_t *ttlp) { | |
37 | ||
8041b5ba | 38 | struct gaih_addrtuple *r_tuple, *r_tuple_prev = NULL; |
e80af1bd | 39 | _cleanup_free_ struct local_address *addresses = NULL; |
5502f0d9 LP |
40 | _cleanup_free_ char *hn = NULL; |
41 | const char *canonical = NULL; | |
a1077c84 | 42 | int n_addresses = 0; |
e8a7a315 | 43 | uint32_t local_address_ipv4; |
5502f0d9 LP |
44 | size_t l, idx, ms; |
45 | char *r_name; | |
4e8c8252 | 46 | |
06202b9e | 47 | PROTECT_ERRNO; |
0c5eb056 LP |
48 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); |
49 | ||
5502f0d9 LP |
50 | assert(name); |
51 | assert(pat); | |
52 | assert(buffer); | |
53 | assert(errnop); | |
54 | assert(h_errnop); | |
55 | ||
56 | if (is_localhost(name)) { | |
a1fdbcbe | 57 | /* We respond to 'localhost', so that /etc/hosts is optional */ |
4e8c8252 | 58 | |
e8a7a315 | 59 | canonical = "localhost"; |
8e38570e | 60 | local_address_ipv4 = htobe32(INADDR_LOOPBACK); |
e9140aff | 61 | |
46a5e0e7 | 62 | } else if (is_gateway_hostname(name)) { |
e9140aff | 63 | |
1d050e1e | 64 | n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses); |
e09e7ac3 LP |
65 | if (n_addresses <= 0) |
66 | goto not_found; | |
e9140aff | 67 | |
5248e7e1 | 68 | canonical = "_gateway"; |
e9140aff | 69 | |
a1fdbcbe LP |
70 | } else if (is_outbound_hostname(name)) { |
71 | ||
72 | n_addresses = local_outbounds(NULL, 0, AF_UNSPEC, &addresses); | |
73 | if (n_addresses <= 0) | |
74 | goto not_found; | |
75 | ||
76 | canonical = "_outbound"; | |
77 | ||
e8a7a315 | 78 | } else { |
5502f0d9 LP |
79 | hn = gethostname_malloc(); |
80 | if (!hn) { | |
cdccd29f | 81 | UNPROTECT_ERRNO; |
0192cbdb | 82 | *errnop = ENOMEM; |
e8a7a315 | 83 | *h_errnop = NO_RECOVERY; |
5502f0d9 | 84 | return NSS_STATUS_TRYAGAIN; |
e8a7a315 LP |
85 | } |
86 | ||
38b38500 | 87 | /* We respond to our local hostname, our hostname suffixed with a single dot. */ |
e09e7ac3 LP |
88 | if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) |
89 | goto not_found; | |
e8a7a315 | 90 | |
1d050e1e | 91 | n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses); |
e80af1bd LP |
92 | if (n_addresses < 0) |
93 | n_addresses = 0; | |
e8a7a315 LP |
94 | |
95 | canonical = hn; | |
96 | local_address_ipv4 = LOCALADDRESS_IPV4; | |
97 | } | |
8041b5ba | 98 | |
e8a7a315 | 99 | l = strlen(canonical); |
db50d326 | 100 | ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 1 + socket_ipv6_is_enabled()); |
4e8c8252 | 101 | if (buflen < ms) { |
cdccd29f | 102 | UNPROTECT_ERRNO; |
0192cbdb | 103 | *errnop = ERANGE; |
cda458a5 | 104 | *h_errnop = NETDB_INTERNAL; |
4e8c8252 LP |
105 | return NSS_STATUS_TRYAGAIN; |
106 | } | |
107 | ||
108 | /* First, fill in hostname */ | |
109 | r_name = buffer; | |
e8a7a315 | 110 | memcpy(r_name, canonical, l+1); |
4e8c8252 LP |
111 | idx = ALIGN(l+1); |
112 | ||
68a9c7c4 ZJS |
113 | assert(n_addresses >= 0); |
114 | if (n_addresses == 0) { | |
8041b5ba | 115 | /* Second, fill in IPv6 tuple */ |
db50d326 YW |
116 | if (socket_ipv6_is_enabled()) { |
117 | r_tuple = (struct gaih_addrtuple*) (buffer + idx); | |
118 | r_tuple->next = r_tuple_prev; | |
119 | r_tuple->name = r_name; | |
120 | r_tuple->family = AF_INET6; | |
121 | memcpy(r_tuple->addr, LOCALADDRESS_IPV6, 16); | |
122 | r_tuple->scopeid = 0; | |
123 | ||
124 | idx += ALIGN(sizeof(struct gaih_addrtuple)); | |
125 | r_tuple_prev = r_tuple; | |
126 | } | |
8041b5ba LP |
127 | |
128 | /* Third, fill in IPv4 tuple */ | |
129 | r_tuple = (struct gaih_addrtuple*) (buffer + idx); | |
130 | r_tuple->next = r_tuple_prev; | |
131 | r_tuple->name = r_name; | |
132 | r_tuple->family = AF_INET; | |
e8a7a315 | 133 | *(uint32_t*) r_tuple->addr = local_address_ipv4; |
a1077c84 | 134 | r_tuple->scopeid = 0; |
8041b5ba LP |
135 | |
136 | idx += ALIGN(sizeof(struct gaih_addrtuple)); | |
137 | r_tuple_prev = r_tuple; | |
138 | } | |
139 | ||
140 | /* Fourth, fill actual addresses in, but in backwards order */ | |
92e9df9c YW |
141 | for (int i = n_addresses; i > 0; i--) { |
142 | struct local_address *a = addresses + i - 1; | |
143 | ||
8041b5ba LP |
144 | r_tuple = (struct gaih_addrtuple*) (buffer + idx); |
145 | r_tuple->next = r_tuple_prev; | |
146 | r_tuple->name = r_name; | |
147 | r_tuple->family = a->family; | |
94876904 | 148 | r_tuple->scopeid = a->family == AF_INET6 && in6_addr_is_link_local(&a->address.in6) ? a->ifindex : 0; |
5502f0d9 | 149 | memcpy(r_tuple->addr, &a->address, 16); |
8041b5ba LP |
150 | |
151 | idx += ALIGN(sizeof(struct gaih_addrtuple)); | |
152 | r_tuple_prev = r_tuple; | |
153 | } | |
4e8c8252 LP |
154 | |
155 | /* Verify the size matches */ | |
156 | assert(idx == ms); | |
157 | ||
d2f1f23a ED |
158 | /* Nscd expects us to store the first record in **pat. */ |
159 | if (*pat) | |
160 | **pat = *r_tuple_prev; | |
161 | else | |
162 | *pat = r_tuple_prev; | |
4e8c8252 LP |
163 | |
164 | if (ttlp) | |
165 | *ttlp = 0; | |
166 | ||
06202b9e YW |
167 | /* Explicitly reset both *h_errnop and h_errno to work around |
168 | * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */ | |
e70df46b LP |
169 | *h_errnop = NETDB_SUCCESS; |
170 | h_errno = 0; | |
171 | ||
4e8c8252 | 172 | return NSS_STATUS_SUCCESS; |
e09e7ac3 LP |
173 | |
174 | not_found: | |
175 | *h_errnop = HOST_NOT_FOUND; | |
176 | return NSS_STATUS_NOTFOUND; | |
4e8c8252 | 177 | } |
6b21f0cf LP |
178 | |
179 | static enum nss_status fill_in_hostent( | |
e8a7a315 | 180 | const char *canonical, const char *additional, |
4e8c8252 | 181 | int af, |
e80af1bd | 182 | struct local_address *addresses, unsigned n_addresses, |
e8a7a315 | 183 | uint32_t local_address_ipv4, |
4e8c8252 LP |
184 | struct hostent *result, |
185 | char *buffer, size_t buflen, | |
0192cbdb | 186 | int *errnop, int *h_errnop, |
4e8c8252 LP |
187 | int32_t *ttlp, |
188 | char **canonp) { | |
189 | ||
d4c9895d | 190 | size_t l_canonical, l_additional, idx, ms, alen; |
e8a7a315 | 191 | char *r_addr, *r_name, *r_aliases, *r_alias = NULL, *r_addr_list; |
e80af1bd | 192 | struct local_address *a; |
e8a7a315 | 193 | unsigned n, c; |
8041b5ba | 194 | |
5502f0d9 | 195 | assert(canonical); |
db50d326 | 196 | assert(IN_SET(af, AF_INET, AF_INET6)); |
5502f0d9 LP |
197 | assert(result); |
198 | assert(buffer); | |
199 | assert(errnop); | |
200 | assert(h_errnop); | |
201 | ||
cdccd29f LP |
202 | PROTECT_ERRNO; |
203 | ||
9d485985 | 204 | alen = FAMILY_ADDRESS_SIZE(af); |
8041b5ba | 205 | |
8041b5ba LP |
206 | for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++) |
207 | if (af == a->family) | |
208 | c++; | |
4e8c8252 | 209 | |
e8a7a315 | 210 | l_canonical = strlen(canonical); |
7bf7ce28 | 211 | l_additional = strlen_ptr(additional); |
e8a7a315 LP |
212 | ms = ALIGN(l_canonical+1)+ |
213 | (additional ? ALIGN(l_additional+1) : 0) + | |
5502f0d9 | 214 | sizeof(char*) + |
e8a7a315 | 215 | (additional ? sizeof(char*) : 0) + |
db50d326 YW |
216 | (c > 0 ? c : af == AF_INET ? 1 : socket_ipv6_is_enabled()) * ALIGN(alen) + |
217 | (c > 0 ? c+1 : af == AF_INET ? 2 : (unsigned) socket_ipv6_is_enabled() + 1) * sizeof(char*); | |
8041b5ba | 218 | |
4e8c8252 | 219 | if (buflen < ms) { |
cdccd29f | 220 | UNPROTECT_ERRNO; |
0192cbdb | 221 | *errnop = ERANGE; |
cda458a5 | 222 | *h_errnop = NETDB_INTERNAL; |
4e8c8252 LP |
223 | return NSS_STATUS_TRYAGAIN; |
224 | } | |
225 | ||
e8a7a315 | 226 | /* First, fill in hostnames */ |
4e8c8252 | 227 | r_name = buffer; |
e8a7a315 LP |
228 | memcpy(r_name, canonical, l_canonical+1); |
229 | idx = ALIGN(l_canonical+1); | |
4e8c8252 | 230 | |
e8a7a315 LP |
231 | if (additional) { |
232 | r_alias = buffer + idx; | |
233 | memcpy(r_alias, additional, l_additional+1); | |
234 | idx += ALIGN(l_additional+1); | |
235 | } | |
236 | ||
237 | /* Second, create aliases array */ | |
4e8c8252 | 238 | r_aliases = buffer + idx; |
e8a7a315 LP |
239 | if (additional) { |
240 | ((char**) r_aliases)[0] = r_alias; | |
241 | ((char**) r_aliases)[1] = NULL; | |
242 | idx += 2*sizeof(char*); | |
243 | } else { | |
244 | ((char**) r_aliases)[0] = NULL; | |
245 | idx += sizeof(char*); | |
246 | } | |
4e8c8252 | 247 | |
8041b5ba | 248 | /* Third, add addresses */ |
4e8c8252 | 249 | r_addr = buffer + idx; |
8041b5ba LP |
250 | if (c > 0) { |
251 | unsigned i = 0; | |
252 | ||
253 | for (a = addresses, n = 0; n < n_addresses; a++, n++) { | |
254 | if (af != a->family) | |
255 | continue; | |
256 | ||
5502f0d9 | 257 | memcpy(r_addr + i*ALIGN(alen), &a->address, alen); |
8041b5ba LP |
258 | i++; |
259 | } | |
260 | ||
261 | assert(i == c); | |
262 | idx += c*ALIGN(alen); | |
8041b5ba | 263 | |
db50d326 YW |
264 | } else if (af == AF_INET) { |
265 | *(uint32_t*) r_addr = local_address_ipv4; | |
266 | idx += ALIGN(alen); | |
267 | } else if (socket_ipv6_is_enabled()) { | |
268 | memcpy(r_addr, LOCALADDRESS_IPV6, 16); | |
8041b5ba LP |
269 | idx += ALIGN(alen); |
270 | } | |
4e8c8252 LP |
271 | |
272 | /* Fourth, add address pointer array */ | |
273 | r_addr_list = buffer + idx; | |
8041b5ba | 274 | if (c > 0) { |
d4c9895d | 275 | unsigned i; |
8041b5ba | 276 | |
d4c9895d LP |
277 | for (i = 0; i < c; i++) |
278 | ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen); | |
8041b5ba | 279 | |
d4c9895d LP |
280 | ((char**) r_addr_list)[i] = NULL; |
281 | idx += (c+1) * sizeof(char*); | |
8041b5ba | 282 | |
db50d326 | 283 | } else if (af == AF_INET || socket_ipv6_is_enabled()) { |
8041b5ba LP |
284 | ((char**) r_addr_list)[0] = r_addr; |
285 | ((char**) r_addr_list)[1] = NULL; | |
d4c9895d | 286 | idx += 2 * sizeof(char*); |
db50d326 YW |
287 | } else { |
288 | ((char**) r_addr_list)[0] = NULL; | |
289 | idx += sizeof(char*); | |
8041b5ba | 290 | } |
4e8c8252 LP |
291 | |
292 | /* Verify the size matches */ | |
293 | assert(idx == ms); | |
294 | ||
295 | result->h_name = r_name; | |
296 | result->h_aliases = (char**) r_aliases; | |
297 | result->h_addrtype = af; | |
298 | result->h_length = alen; | |
299 | result->h_addr_list = (char**) r_addr_list; | |
300 | ||
301 | if (ttlp) | |
302 | *ttlp = 0; | |
303 | ||
304 | if (canonp) | |
305 | *canonp = r_name; | |
306 | ||
06202b9e YW |
307 | /* Explicitly reset both *h_errnop and h_errno to work around |
308 | * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */ | |
e70df46b LP |
309 | *h_errnop = NETDB_SUCCESS; |
310 | h_errno = 0; | |
311 | ||
4e8c8252 | 312 | return NSS_STATUS_SUCCESS; |
6b21f0cf LP |
313 | } |
314 | ||
4e8c8252 LP |
315 | enum nss_status _nss_myhostname_gethostbyname3_r( |
316 | const char *name, | |
317 | int af, | |
318 | struct hostent *host, | |
319 | char *buffer, size_t buflen, | |
320 | int *errnop, int *h_errnop, | |
321 | int32_t *ttlp, | |
322 | char **canonp) { | |
6b21f0cf | 323 | |
e80af1bd | 324 | _cleanup_free_ struct local_address *addresses = NULL; |
e8a7a315 | 325 | const char *canonical, *additional = NULL; |
5502f0d9 | 326 | _cleanup_free_ char *hn = NULL; |
e9140aff | 327 | uint32_t local_address_ipv4 = 0; |
e80af1bd | 328 | int n_addresses = 0; |
5502f0d9 | 329 | |
06202b9e | 330 | PROTECT_ERRNO; |
0c5eb056 LP |
331 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); |
332 | ||
5502f0d9 LP |
333 | assert(name); |
334 | assert(host); | |
335 | assert(buffer); | |
336 | assert(errnop); | |
337 | assert(h_errnop); | |
6b21f0cf | 338 | |
4e8c8252 LP |
339 | if (af == AF_UNSPEC) |
340 | af = AF_INET; | |
6b21f0cf | 341 | |
ec2ce0c5 | 342 | if (!IN_SET(af, AF_INET, AF_INET6)) { |
cdccd29f | 343 | UNPROTECT_ERRNO; |
0192cbdb | 344 | *errnop = EAFNOSUPPORT; |
4e8c8252 LP |
345 | *h_errnop = NO_DATA; |
346 | return NSS_STATUS_UNAVAIL; | |
347 | } | |
6b21f0cf | 348 | |
5502f0d9 | 349 | if (is_localhost(name)) { |
db50d326 YW |
350 | if (af == AF_INET6 && !socket_ipv6_is_enabled()) |
351 | goto not_found; | |
352 | ||
e8a7a315 | 353 | canonical = "localhost"; |
8e38570e | 354 | local_address_ipv4 = htobe32(INADDR_LOOPBACK); |
e9140aff | 355 | |
46a5e0e7 | 356 | } else if (is_gateway_hostname(name)) { |
e9140aff | 357 | |
1d050e1e | 358 | n_addresses = local_gateways(NULL, 0, af, &addresses); |
e09e7ac3 LP |
359 | if (n_addresses <= 0) |
360 | goto not_found; | |
e9140aff | 361 | |
5248e7e1 | 362 | canonical = "_gateway"; |
e9140aff | 363 | |
a1fdbcbe LP |
364 | } else if (is_outbound_hostname(name)) { |
365 | ||
366 | n_addresses = local_outbounds(NULL, 0, af, &addresses); | |
367 | if (n_addresses <= 0) | |
368 | goto not_found; | |
369 | ||
370 | canonical = "_outbound"; | |
371 | ||
e8a7a315 | 372 | } else { |
5502f0d9 LP |
373 | hn = gethostname_malloc(); |
374 | if (!hn) { | |
cdccd29f | 375 | UNPROTECT_ERRNO; |
0192cbdb | 376 | *errnop = ENOMEM; |
e8a7a315 | 377 | *h_errnop = NO_RECOVERY; |
5502f0d9 | 378 | return NSS_STATUS_TRYAGAIN; |
e8a7a315 | 379 | } |
6b21f0cf | 380 | |
e09e7ac3 LP |
381 | if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) |
382 | goto not_found; | |
e8a7a315 | 383 | |
1d050e1e | 384 | n_addresses = local_addresses(NULL, 0, af, &addresses); |
e80af1bd LP |
385 | if (n_addresses < 0) |
386 | n_addresses = 0; | |
e8a7a315 LP |
387 | |
388 | canonical = hn; | |
389 | additional = n_addresses <= 0 && af == AF_INET6 ? "localhost" : NULL; | |
390 | local_address_ipv4 = LOCALADDRESS_IPV4; | |
4e8c8252 | 391 | } |
6b21f0cf | 392 | |
cdccd29f LP |
393 | UNPROTECT_ERRNO; |
394 | ||
e8a7a315 LP |
395 | return fill_in_hostent( |
396 | canonical, additional, | |
397 | af, | |
398 | addresses, n_addresses, | |
399 | local_address_ipv4, | |
400 | host, | |
401 | buffer, buflen, | |
0192cbdb | 402 | errnop, h_errnop, |
e8a7a315 LP |
403 | ttlp, |
404 | canonp); | |
e09e7ac3 LP |
405 | |
406 | not_found: | |
407 | *h_errnop = HOST_NOT_FOUND; | |
408 | return NSS_STATUS_NOTFOUND; | |
4e8c8252 | 409 | } |
6b21f0cf | 410 | |
4e8c8252 LP |
411 | enum nss_status _nss_myhostname_gethostbyaddr2_r( |
412 | const void* addr, socklen_t len, | |
413 | int af, | |
414 | struct hostent *host, | |
415 | char *buffer, size_t buflen, | |
416 | int *errnop, int *h_errnop, | |
417 | int32_t *ttlp) { | |
6b21f0cf | 418 | |
e8a7a315 | 419 | const char *canonical = NULL, *additional = NULL; |
5502f0d9 | 420 | uint32_t local_address_ipv4 = LOCALADDRESS_IPV4; |
e80af1bd | 421 | _cleanup_free_ struct local_address *addresses = NULL; |
5502f0d9 | 422 | _cleanup_free_ char *hn = NULL; |
e80af1bd LP |
423 | int n_addresses = 0; |
424 | struct local_address *a; | |
3fdcecc8 | 425 | bool additional_from_hostname = false; |
e80af1bd | 426 | unsigned n; |
5502f0d9 | 427 | |
06202b9e | 428 | PROTECT_ERRNO; |
0c5eb056 LP |
429 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); |
430 | ||
5502f0d9 LP |
431 | assert(addr); |
432 | assert(host); | |
433 | assert(buffer); | |
434 | assert(errnop); | |
435 | assert(h_errnop); | |
8041b5ba | 436 | |
555bd6e9 | 437 | if (!IN_SET(af, AF_INET, AF_INET6)) { |
cdccd29f | 438 | UNPROTECT_ERRNO; |
0192cbdb | 439 | *errnop = EAFNOSUPPORT; |
555bd6e9 LP |
440 | *h_errnop = NO_DATA; |
441 | return NSS_STATUS_UNAVAIL; | |
442 | } | |
443 | ||
9d485985 | 444 | if (len != FAMILY_ADDRESS_SIZE(af)) { |
cdccd29f | 445 | UNPROTECT_ERRNO; |
0192cbdb | 446 | *errnop = EINVAL; |
8041b5ba LP |
447 | *h_errnop = NO_RECOVERY; |
448 | return NSS_STATUS_UNAVAIL; | |
449 | } | |
6b21f0cf | 450 | |
4e8c8252 | 451 | if (af == AF_INET) { |
8041b5ba LP |
452 | if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4) |
453 | goto found; | |
6b21f0cf | 454 | |
8e38570e | 455 | if ((*(uint32_t*) addr) == htobe32(INADDR_LOOPBACK)) { |
e8a7a315 | 456 | canonical = "localhost"; |
8e38570e | 457 | local_address_ipv4 = htobe32(INADDR_LOOPBACK); |
e8a7a315 LP |
458 | goto found; |
459 | } | |
460 | ||
555bd6e9 LP |
461 | } else { |
462 | assert(af == AF_INET6); | |
8041b5ba | 463 | |
db50d326 YW |
464 | if (socket_ipv6_is_enabled()) |
465 | goto not_found; | |
466 | ||
e8a7a315 | 467 | if (memcmp(addr, LOCALADDRESS_IPV6, 16) == 0) { |
3fdcecc8 LP |
468 | canonical = "localhost"; |
469 | additional_from_hostname = true; | |
8041b5ba | 470 | goto found; |
e8a7a315 | 471 | } |
4e8c8252 LP |
472 | } |
473 | ||
db50d326 YW |
474 | n_addresses = local_addresses(NULL, 0, af, &addresses); |
475 | for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) | |
68a9c7c4 ZJS |
476 | if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) |
477 | goto found; | |
e9140aff | 478 | |
97b11eed | 479 | addresses = mfree(addresses); |
e9140aff | 480 | |
db50d326 YW |
481 | n_addresses = local_gateways(NULL, 0, af, &addresses); |
482 | for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) | |
68a9c7c4 | 483 | if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) { |
5248e7e1 | 484 | canonical = "_gateway"; |
68a9c7c4 | 485 | goto found; |
e9140aff | 486 | } |
8041b5ba | 487 | |
db50d326 | 488 | not_found: |
8041b5ba | 489 | *h_errnop = HOST_NOT_FOUND; |
8041b5ba LP |
490 | return NSS_STATUS_NOTFOUND; |
491 | ||
492 | found: | |
82e4c2d6 | 493 | if (!canonical || additional_from_hostname) { |
3fdcecc8 LP |
494 | hn = gethostname_malloc(); |
495 | if (!hn) { | |
cdccd29f | 496 | UNPROTECT_ERRNO; |
0192cbdb | 497 | *errnop = ENOMEM; |
3fdcecc8 LP |
498 | *h_errnop = NO_RECOVERY; |
499 | return NSS_STATUS_TRYAGAIN; | |
500 | } | |
501 | ||
502 | if (!canonical) | |
503 | canonical = hn; | |
82e4c2d6 | 504 | else |
3fdcecc8 LP |
505 | additional = hn; |
506 | } | |
4e8c8252 | 507 | |
cdccd29f | 508 | UNPROTECT_ERRNO; |
e8a7a315 LP |
509 | return fill_in_hostent( |
510 | canonical, additional, | |
511 | af, | |
512 | addresses, n_addresses, | |
513 | local_address_ipv4, | |
514 | host, | |
515 | buffer, buflen, | |
0192cbdb | 516 | errnop, h_errnop, |
e8a7a315 LP |
517 | ttlp, |
518 | NULL); | |
4e8c8252 | 519 | } |
6b21f0cf | 520 | |
c9fdc26e LP |
521 | NSS_GETHOSTBYNAME_FALLBACKS(myhostname); |
522 | NSS_GETHOSTBYADDR_FALLBACKS(myhostname); |