Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <errno.h>
4 : #include <netdb.h>
5 : #include <nss.h>
6 : #include <stdlib.h>
7 : #include <string.h>
8 : #include <sys/types.h>
9 : #include <unistd.h>
10 :
11 : #include "sd-bus.h"
12 :
13 : #include "bus-common-errors.h"
14 : #include "errno-util.h"
15 : #include "in-addr-util.h"
16 : #include "macro.h"
17 : #include "nss-util.h"
18 : #include "resolved-def.h"
19 : #include "signal-util.h"
20 : #include "string-util.h"
21 :
22 : NSS_GETHOSTBYNAME_PROTOTYPES(resolve);
23 : NSS_GETHOSTBYADDR_PROTOTYPES(resolve);
24 :
25 0 : static bool bus_error_shall_fallback(sd_bus_error *e) {
26 0 : return sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN) ||
27 0 : sd_bus_error_has_name(e, SD_BUS_ERROR_NAME_HAS_NO_OWNER) ||
28 0 : sd_bus_error_has_name(e, SD_BUS_ERROR_NO_REPLY) ||
29 0 : sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED) ||
30 0 : sd_bus_error_has_name(e, SD_BUS_ERROR_DISCONNECTED) ||
31 0 : sd_bus_error_has_name(e, SD_BUS_ERROR_TIMEOUT);
32 : }
33 :
34 0 : static int count_addresses(sd_bus_message *m, int af, const char **canonical) {
35 0 : int c = 0, r;
36 :
37 0 : assert(m);
38 0 : assert(canonical);
39 :
40 0 : r = sd_bus_message_enter_container(m, 'a', "(iiay)");
41 0 : if (r < 0)
42 0 : return r;
43 :
44 0 : while ((r = sd_bus_message_enter_container(m, 'r', "iiay")) > 0) {
45 : int family, ifindex;
46 :
47 : assert_cc(sizeof(int32_t) == sizeof(int));
48 :
49 0 : r = sd_bus_message_read(m, "ii", &ifindex, &family);
50 0 : if (r < 0)
51 0 : return r;
52 :
53 0 : r = sd_bus_message_skip(m, "ay");
54 0 : if (r < 0)
55 0 : return r;
56 :
57 0 : r = sd_bus_message_exit_container(m);
58 0 : if (r < 0)
59 0 : return r;
60 :
61 0 : if (af != AF_UNSPEC && family != af)
62 0 : continue;
63 :
64 0 : c++;
65 : }
66 0 : if (r < 0)
67 0 : return r;
68 :
69 0 : r = sd_bus_message_exit_container(m);
70 0 : if (r < 0)
71 0 : return r;
72 :
73 0 : r = sd_bus_message_read(m, "s", canonical);
74 0 : if (r < 0)
75 0 : return r;
76 :
77 0 : r = sd_bus_message_rewind(m, true);
78 0 : if (r < 0)
79 0 : return r;
80 :
81 0 : return c;
82 : }
83 :
84 0 : static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) {
85 : struct in6_addr in6;
86 :
87 0 : if (family != AF_INET6)
88 0 : return 0;
89 :
90 : /* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */
91 :
92 0 : assert(sizeof(in6) == FAMILY_ADDRESS_SIZE(AF_INET6));
93 0 : memcpy(&in6, a, sizeof(struct in6_addr));
94 :
95 0 : return IN6_IS_ADDR_LINKLOCAL(&in6) ? ifindex : 0;
96 : }
97 :
98 0 : static bool avoid_deadlock(void) {
99 :
100 : /* Check whether this lookup might have a chance of deadlocking because we are called from the service manager
101 : * code activating systemd-resolved.service. After all, we shouldn't synchronously do lookups to
102 : * systemd-resolved if we are required to finish before it can be started. This of course won't detect all
103 : * possible dead locks of this kind, but it should work for the most obvious cases. */
104 :
105 0 : if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */
106 0 : return false;
107 :
108 0 : return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-resolved.service") &&
109 0 : streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system");
110 : }
111 :
112 0 : enum nss_status _nss_resolve_gethostbyname4_r(
113 : const char *name,
114 : struct gaih_addrtuple **pat,
115 : char *buffer, size_t buflen,
116 : int *errnop, int *h_errnop,
117 : int32_t *ttlp) {
118 :
119 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
120 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
121 0 : struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL;
122 0 : _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
123 0 : const char *canonical = NULL;
124 : size_t l, ms, idx;
125 : char *r_name;
126 0 : int c, r, i = 0;
127 :
128 0 : PROTECT_ERRNO;
129 0 : BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
130 :
131 0 : assert(name);
132 0 : assert(pat);
133 0 : assert(buffer);
134 0 : assert(errnop);
135 0 : assert(h_errnop);
136 :
137 0 : if (avoid_deadlock()) {
138 0 : r = -EDEADLK;
139 0 : goto fail;
140 : }
141 :
142 0 : r = sd_bus_open_system(&bus);
143 0 : if (r < 0)
144 0 : goto fail;
145 :
146 0 : r = sd_bus_message_new_method_call(
147 : bus,
148 : &req,
149 : "org.freedesktop.resolve1",
150 : "/org/freedesktop/resolve1",
151 : "org.freedesktop.resolve1.Manager",
152 : "ResolveHostname");
153 0 : if (r < 0)
154 0 : goto fail;
155 :
156 0 : r = sd_bus_message_set_auto_start(req, false);
157 0 : if (r < 0)
158 0 : goto fail;
159 :
160 0 : r = sd_bus_message_append(req, "isit", 0, name, AF_UNSPEC, (uint64_t) 0);
161 0 : if (r < 0)
162 0 : goto fail;
163 :
164 0 : r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
165 0 : if (r < 0) {
166 0 : if (!bus_error_shall_fallback(&error))
167 0 : goto not_found;
168 :
169 : /* Return NSS_STATUS_UNAVAIL when communication with systemd-resolved fails,
170 : allowing falling back to other nss modules. Treat all other error conditions as
171 : NOTFOUND. This includes DNSSEC errors and suchlike. (We don't use UNAVAIL in this
172 : case so that the nsswitch.conf configuration can distinguish such executed but
173 : negative replies from complete failure to talk to resolved). */
174 0 : goto fail;
175 : }
176 :
177 0 : c = count_addresses(reply, AF_UNSPEC, &canonical);
178 0 : if (c < 0) {
179 0 : r = c;
180 0 : goto fail;
181 : }
182 0 : if (c == 0)
183 0 : goto not_found;
184 :
185 0 : if (isempty(canonical))
186 0 : canonical = name;
187 :
188 0 : l = strlen(canonical);
189 0 : ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c;
190 0 : if (buflen < ms) {
191 0 : UNPROTECT_ERRNO;
192 0 : *errnop = ERANGE;
193 0 : *h_errnop = NETDB_INTERNAL;
194 0 : return NSS_STATUS_TRYAGAIN;
195 : }
196 :
197 : /* First, append name */
198 0 : r_name = buffer;
199 0 : memcpy(r_name, canonical, l+1);
200 0 : idx = ALIGN(l+1);
201 :
202 : /* Second, append addresses */
203 0 : r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
204 :
205 0 : r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
206 0 : if (r < 0)
207 0 : goto fail;
208 :
209 0 : while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
210 : int family, ifindex;
211 : const void *a;
212 : size_t sz;
213 :
214 : assert_cc(sizeof(int32_t) == sizeof(int));
215 :
216 0 : r = sd_bus_message_read(reply, "ii", &ifindex, &family);
217 0 : if (r < 0)
218 0 : goto fail;
219 :
220 0 : if (ifindex < 0) {
221 0 : r = -EINVAL;
222 0 : goto fail;
223 : }
224 :
225 0 : r = sd_bus_message_read_array(reply, 'y', &a, &sz);
226 0 : if (r < 0)
227 0 : goto fail;
228 :
229 0 : r = sd_bus_message_exit_container(reply);
230 0 : if (r < 0)
231 0 : goto fail;
232 :
233 0 : if (!IN_SET(family, AF_INET, AF_INET6))
234 0 : continue;
235 :
236 0 : if (sz != FAMILY_ADDRESS_SIZE(family)) {
237 0 : r = -EINVAL;
238 0 : goto fail;
239 : }
240 :
241 0 : r_tuple = (struct gaih_addrtuple*) (buffer + idx);
242 0 : r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
243 0 : r_tuple->name = r_name;
244 0 : r_tuple->family = family;
245 0 : r_tuple->scopeid = ifindex_to_scopeid(family, a, ifindex);
246 0 : memcpy(r_tuple->addr, a, sz);
247 :
248 0 : idx += ALIGN(sizeof(struct gaih_addrtuple));
249 0 : i++;
250 : }
251 0 : if (r < 0)
252 0 : goto fail;
253 :
254 0 : assert(i == c);
255 0 : assert(idx == ms);
256 :
257 0 : if (*pat)
258 0 : **pat = *r_tuple_first;
259 : else
260 0 : *pat = r_tuple_first;
261 :
262 0 : if (ttlp)
263 0 : *ttlp = 0;
264 :
265 : /* Explicitly reset both *h_errnop and h_errno to work around
266 : * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
267 0 : *h_errnop = NETDB_SUCCESS;
268 0 : h_errno = 0;
269 :
270 0 : return NSS_STATUS_SUCCESS;
271 :
272 0 : fail:
273 0 : UNPROTECT_ERRNO;
274 0 : *errnop = -r;
275 0 : *h_errnop = NO_RECOVERY;
276 0 : return NSS_STATUS_UNAVAIL;
277 :
278 0 : not_found:
279 0 : *h_errnop = HOST_NOT_FOUND;
280 0 : return NSS_STATUS_NOTFOUND;
281 : }
282 :
283 0 : enum nss_status _nss_resolve_gethostbyname3_r(
284 : const char *name,
285 : int af,
286 : struct hostent *result,
287 : char *buffer, size_t buflen,
288 : int *errnop, int *h_errnop,
289 : int32_t *ttlp,
290 : char **canonp) {
291 :
292 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
293 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
294 : char *r_name, *r_aliases, *r_addr, *r_addr_list;
295 0 : _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
296 : size_t l, idx, ms, alen;
297 : const char *canonical;
298 0 : int c, r, i = 0;
299 :
300 0 : PROTECT_ERRNO;
301 0 : BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
302 :
303 0 : assert(name);
304 0 : assert(result);
305 0 : assert(buffer);
306 0 : assert(errnop);
307 0 : assert(h_errnop);
308 :
309 0 : if (af == AF_UNSPEC)
310 0 : af = AF_INET;
311 :
312 0 : if (!IN_SET(af, AF_INET, AF_INET6)) {
313 0 : r = -EAFNOSUPPORT;
314 0 : goto fail;
315 : }
316 :
317 0 : if (avoid_deadlock()) {
318 0 : r = -EDEADLK;
319 0 : goto fail;
320 : }
321 :
322 0 : r = sd_bus_open_system(&bus);
323 0 : if (r < 0)
324 0 : goto fail;
325 :
326 0 : r = sd_bus_message_new_method_call(
327 : bus,
328 : &req,
329 : "org.freedesktop.resolve1",
330 : "/org/freedesktop/resolve1",
331 : "org.freedesktop.resolve1.Manager",
332 : "ResolveHostname");
333 0 : if (r < 0)
334 0 : goto fail;
335 :
336 0 : r = sd_bus_message_set_auto_start(req, false);
337 0 : if (r < 0)
338 0 : goto fail;
339 :
340 0 : r = sd_bus_message_append(req, "isit", 0, name, af, (uint64_t) 0);
341 0 : if (r < 0)
342 0 : goto fail;
343 :
344 0 : r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
345 0 : if (r < 0) {
346 0 : if (!bus_error_shall_fallback(&error))
347 0 : goto not_found;
348 :
349 0 : goto fail;
350 : }
351 :
352 0 : c = count_addresses(reply, af, &canonical);
353 0 : if (c < 0) {
354 0 : r = c;
355 0 : goto fail;
356 : }
357 0 : if (c == 0)
358 0 : goto not_found;
359 :
360 0 : if (isempty(canonical))
361 0 : canonical = name;
362 :
363 0 : alen = FAMILY_ADDRESS_SIZE(af);
364 0 : l = strlen(canonical);
365 :
366 0 : ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*);
367 :
368 0 : if (buflen < ms) {
369 0 : UNPROTECT_ERRNO;
370 0 : *errnop = ERANGE;
371 0 : *h_errnop = NETDB_INTERNAL;
372 0 : return NSS_STATUS_TRYAGAIN;
373 : }
374 :
375 : /* First, append name */
376 0 : r_name = buffer;
377 0 : memcpy(r_name, canonical, l+1);
378 0 : idx = ALIGN(l+1);
379 :
380 : /* Second, create empty aliases array */
381 0 : r_aliases = buffer + idx;
382 0 : ((char**) r_aliases)[0] = NULL;
383 0 : idx += sizeof(char*);
384 :
385 : /* Third, append addresses */
386 0 : r_addr = buffer + idx;
387 :
388 0 : r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
389 0 : if (r < 0)
390 0 : goto fail;
391 :
392 0 : while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
393 : int ifindex, family;
394 : const void *a;
395 : size_t sz;
396 :
397 0 : r = sd_bus_message_read(reply, "ii", &ifindex, &family);
398 0 : if (r < 0)
399 0 : goto fail;
400 :
401 0 : if (ifindex < 0) {
402 0 : r = -EINVAL;
403 0 : goto fail;
404 : }
405 :
406 0 : r = sd_bus_message_read_array(reply, 'y', &a, &sz);
407 0 : if (r < 0)
408 0 : goto fail;
409 :
410 0 : r = sd_bus_message_exit_container(reply);
411 0 : if (r < 0)
412 0 : goto fail;
413 :
414 0 : if (family != af)
415 0 : continue;
416 :
417 0 : if (sz != alen) {
418 0 : r = -EINVAL;
419 0 : goto fail;
420 : }
421 :
422 0 : memcpy(r_addr + i*ALIGN(alen), a, alen);
423 0 : i++;
424 : }
425 0 : if (r < 0)
426 0 : goto fail;
427 :
428 0 : assert(i == c);
429 0 : idx += c * ALIGN(alen);
430 :
431 : /* Fourth, append address pointer array */
432 0 : r_addr_list = buffer + idx;
433 0 : for (i = 0; i < c; i++)
434 0 : ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
435 :
436 0 : ((char**) r_addr_list)[i] = NULL;
437 0 : idx += (c+1) * sizeof(char*);
438 :
439 0 : assert(idx == ms);
440 :
441 0 : result->h_name = r_name;
442 0 : result->h_aliases = (char**) r_aliases;
443 0 : result->h_addrtype = af;
444 0 : result->h_length = alen;
445 0 : result->h_addr_list = (char**) r_addr_list;
446 :
447 0 : if (ttlp)
448 0 : *ttlp = 0;
449 :
450 0 : if (canonp)
451 0 : *canonp = r_name;
452 :
453 : /* Explicitly reset both *h_errnop and h_errno to work around
454 : * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
455 0 : *h_errnop = NETDB_SUCCESS;
456 0 : h_errno = 0;
457 :
458 0 : return NSS_STATUS_SUCCESS;
459 :
460 0 : fail:
461 0 : UNPROTECT_ERRNO;
462 0 : *errnop = -r;
463 0 : *h_errnop = NO_RECOVERY;
464 0 : return NSS_STATUS_UNAVAIL;
465 :
466 0 : not_found:
467 0 : *h_errnop = HOST_NOT_FOUND;
468 0 : return NSS_STATUS_NOTFOUND;
469 : }
470 :
471 0 : enum nss_status _nss_resolve_gethostbyaddr2_r(
472 : const void* addr, socklen_t len,
473 : int af,
474 : struct hostent *result,
475 : char *buffer, size_t buflen,
476 : int *errnop, int *h_errnop,
477 : int32_t *ttlp) {
478 :
479 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
480 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
481 : char *r_name, *r_aliases, *r_addr, *r_addr_list;
482 0 : _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
483 0 : unsigned c = 0, i = 0;
484 0 : size_t ms = 0, idx;
485 : const char *n;
486 : int r, ifindex;
487 :
488 0 : PROTECT_ERRNO;
489 0 : BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
490 :
491 0 : assert(addr);
492 0 : assert(result);
493 0 : assert(buffer);
494 0 : assert(errnop);
495 0 : assert(h_errnop);
496 :
497 0 : if (!IN_SET(af, AF_INET, AF_INET6)) {
498 0 : UNPROTECT_ERRNO;
499 0 : *errnop = EAFNOSUPPORT;
500 0 : *h_errnop = NO_DATA;
501 0 : return NSS_STATUS_UNAVAIL;
502 : }
503 :
504 0 : if (len != FAMILY_ADDRESS_SIZE(af)) {
505 0 : r = -EINVAL;
506 0 : goto fail;
507 : }
508 :
509 0 : if (avoid_deadlock()) {
510 0 : r = -EDEADLK;
511 0 : goto fail;
512 : }
513 :
514 0 : r = sd_bus_open_system(&bus);
515 0 : if (r < 0)
516 0 : goto fail;
517 :
518 0 : r = sd_bus_message_new_method_call(
519 : bus,
520 : &req,
521 : "org.freedesktop.resolve1",
522 : "/org/freedesktop/resolve1",
523 : "org.freedesktop.resolve1.Manager",
524 : "ResolveAddress");
525 0 : if (r < 0)
526 0 : goto fail;
527 :
528 0 : r = sd_bus_message_set_auto_start(req, false);
529 0 : if (r < 0)
530 0 : goto fail;
531 :
532 0 : r = sd_bus_message_append(req, "ii", 0, af);
533 0 : if (r < 0)
534 0 : goto fail;
535 :
536 0 : r = sd_bus_message_append_array(req, 'y', addr, len);
537 0 : if (r < 0)
538 0 : goto fail;
539 :
540 0 : r = sd_bus_message_append(req, "t", (uint64_t) 0);
541 0 : if (r < 0)
542 0 : goto fail;
543 :
544 0 : r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
545 0 : if (r < 0) {
546 0 : if (!bus_error_shall_fallback(&error))
547 0 : goto not_found;
548 :
549 0 : goto fail;
550 : }
551 :
552 0 : r = sd_bus_message_enter_container(reply, 'a', "(is)");
553 0 : if (r < 0)
554 0 : goto fail;
555 :
556 0 : while ((r = sd_bus_message_read(reply, "(is)", &ifindex, &n)) > 0) {
557 :
558 0 : if (ifindex < 0) {
559 0 : r = -EINVAL;
560 0 : goto fail;
561 : }
562 :
563 0 : c++;
564 0 : ms += ALIGN(strlen(n) + 1);
565 : }
566 0 : if (r < 0)
567 0 : goto fail;
568 :
569 0 : r = sd_bus_message_rewind(reply, false);
570 0 : if (r < 0)
571 0 : goto fail;
572 :
573 0 : if (c <= 0)
574 0 : goto not_found;
575 :
576 0 : ms += ALIGN(len) + /* the address */
577 0 : 2 * sizeof(char*) + /* pointers to the address, plus trailing NULL */
578 0 : c * sizeof(char*); /* pointers to aliases, plus trailing NULL */
579 :
580 0 : if (buflen < ms) {
581 0 : UNPROTECT_ERRNO;
582 0 : *errnop = ERANGE;
583 0 : *h_errnop = NETDB_INTERNAL;
584 0 : return NSS_STATUS_TRYAGAIN;
585 : }
586 :
587 : /* First, place address */
588 0 : r_addr = buffer;
589 0 : memcpy(r_addr, addr, len);
590 0 : idx = ALIGN(len);
591 :
592 : /* Second, place address list */
593 0 : r_addr_list = buffer + idx;
594 0 : ((char**) r_addr_list)[0] = r_addr;
595 0 : ((char**) r_addr_list)[1] = NULL;
596 0 : idx += sizeof(char*) * 2;
597 :
598 : /* Third, reserve space for the aliases array */
599 0 : r_aliases = buffer + idx;
600 0 : idx += sizeof(char*) * c;
601 :
602 : /* Fourth, place aliases */
603 0 : i = 0;
604 0 : r_name = buffer + idx;
605 0 : while ((r = sd_bus_message_read(reply, "(is)", &ifindex, &n)) > 0) {
606 : char *p;
607 : size_t l;
608 :
609 0 : l = strlen(n);
610 0 : p = buffer + idx;
611 0 : memcpy(p, n, l+1);
612 :
613 0 : if (i > 0)
614 0 : ((char**) r_aliases)[i-1] = p;
615 0 : i++;
616 :
617 0 : idx += ALIGN(l+1);
618 : }
619 0 : if (r < 0)
620 0 : goto fail;
621 :
622 0 : ((char**) r_aliases)[c-1] = NULL;
623 0 : assert(idx == ms);
624 :
625 0 : result->h_name = r_name;
626 0 : result->h_aliases = (char**) r_aliases;
627 0 : result->h_addrtype = af;
628 0 : result->h_length = len;
629 0 : result->h_addr_list = (char**) r_addr_list;
630 :
631 0 : if (ttlp)
632 0 : *ttlp = 0;
633 :
634 : /* Explicitly reset both *h_errnop and h_errno to work around
635 : * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
636 0 : *h_errnop = NETDB_SUCCESS;
637 0 : h_errno = 0;
638 :
639 0 : return NSS_STATUS_SUCCESS;
640 :
641 0 : fail:
642 0 : UNPROTECT_ERRNO;
643 0 : *errnop = -r;
644 0 : *h_errnop = NO_RECOVERY;
645 0 : return NSS_STATUS_UNAVAIL;
646 :
647 0 : not_found:
648 0 : *h_errnop = HOST_NOT_FOUND;
649 0 : return NSS_STATUS_NOTFOUND;
650 : }
651 :
652 0 : NSS_GETHOSTBYNAME_FALLBACKS(resolve);
653 0 : NSS_GETHOSTBYADDR_FALLBACKS(resolve);
|