1 | /* $NetBSD: gethnamaddr.c,v 1.92 2015/09/22 16:16:02 christos Exp $ */ |
2 | |
3 | /* |
4 | * ++Copyright++ 1985, 1988, 1993 |
5 | * - |
6 | * Copyright (c) 1985, 1988, 1993 |
7 | * The Regents of the University of California. All rights reserved. |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions |
11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. Neither the name of the University nor the names of its contributors |
18 | * may be used to endorse or promote products derived from this software |
19 | * without specific prior written permission. |
20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
31 | * SUCH DAMAGE. |
32 | * - |
33 | * Portions Copyright (c) 1993 by Digital Equipment Corporation. |
34 | * |
35 | * Permission to use, copy, modify, and distribute this software for any |
36 | * purpose with or without fee is hereby granted, provided that the above |
37 | * copyright notice and this permission notice appear in all copies, and that |
38 | * the name of Digital Equipment Corporation not be used in advertising or |
39 | * publicity pertaining to distribution of the document or software without |
40 | * specific, written prior permission. |
41 | * |
42 | * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL |
43 | * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES |
44 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT |
45 | * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
46 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
47 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS |
48 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
49 | * SOFTWARE. |
50 | * - |
51 | * --Copyright-- |
52 | */ |
53 | |
54 | #include <sys/cdefs.h> |
55 | #if defined(LIBC_SCCS) && !defined(lint) |
56 | #if 0 |
57 | static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93" ; |
58 | static char rcsid[] = "Id: gethnamaddr.c,v 8.21 1997/06/01 20:34:37 vixie Exp " ; |
59 | #else |
60 | __RCSID("$NetBSD: gethnamaddr.c,v 1.92 2015/09/22 16:16:02 christos Exp $" ); |
61 | #endif |
62 | #endif /* LIBC_SCCS and not lint */ |
63 | |
64 | #if defined(_LIBC) |
65 | #include "namespace.h" |
66 | #endif |
67 | #include <sys/param.h> |
68 | #include <sys/socket.h> |
69 | #include <netinet/in.h> |
70 | #include <arpa/inet.h> |
71 | #include <arpa/nameser.h> |
72 | |
73 | #include <assert.h> |
74 | #include <ctype.h> |
75 | #include <errno.h> |
76 | #include <netdb.h> |
77 | #include <resolv.h> |
78 | #include <stdarg.h> |
79 | #include <stdio.h> |
80 | #include <syslog.h> |
81 | |
82 | #ifndef LOG_AUTH |
83 | # define LOG_AUTH 0 |
84 | #endif |
85 | |
86 | #define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */ |
87 | |
88 | #include <nsswitch.h> |
89 | #include <stdlib.h> |
90 | #include <string.h> |
91 | |
92 | #ifdef YP |
93 | #include <rpc/rpc.h> |
94 | #include <rpcsvc/yp_prot.h> |
95 | #include <rpcsvc/ypclnt.h> |
96 | #endif |
97 | |
98 | #include "hostent.h" |
99 | |
100 | #if defined(_LIBC) && defined(__weak_alias) |
101 | __weak_alias(gethostbyaddr,_gethostbyaddr) |
102 | __weak_alias(gethostbyname,_gethostbyname) |
103 | __weak_alias(gethostent,_gethostent) |
104 | #endif |
105 | |
106 | #define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \ |
107 | (ok)(nm) != 0) |
108 | #define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok) |
109 | #define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok) |
110 | |
111 | #define addalias(d, s, arr, siz) do { \ |
112 | if (d >= &arr[siz]) { \ |
113 | char **xptr = realloc(arr, (siz + 10) * sizeof(*arr)); \ |
114 | if (xptr == NULL) \ |
115 | goto nospc; \ |
116 | d = xptr + (d - arr); \ |
117 | arr = xptr; \ |
118 | siz += 10; \ |
119 | } \ |
120 | *d++ = s; \ |
121 | } while (/*CONSTCOND*/0) |
122 | |
123 | #define setup(arr, siz) do { \ |
124 | arr = malloc((siz = 10) * sizeof(*arr)); \ |
125 | if (arr == NULL) \ |
126 | goto nospc; \ |
127 | } while (/*CONSTCOND*/0) |
128 | |
129 | |
130 | static const char AskedForGot[] = |
131 | "gethostby*.getanswer: asked for \"%s\", got \"%s\"" ; |
132 | |
133 | |
134 | #ifdef YP |
135 | static char *__ypdomain; |
136 | #endif |
137 | |
138 | #define MAXPACKET (64*1024) |
139 | |
140 | typedef union { |
141 | HEADER hdr; |
142 | u_char buf[MAXPACKET]; |
143 | } querybuf; |
144 | |
145 | typedef union { |
146 | int32_t al; |
147 | char ac; |
148 | } align; |
149 | |
150 | #ifdef DEBUG |
151 | static void debugprintf(const char *, res_state, ...) |
152 | __attribute__((__format__(__printf__, 1, 3))); |
153 | #endif |
154 | static struct hostent *getanswer(const querybuf *, int, const char *, int, |
155 | res_state, struct hostent *, char *, size_t, int *); |
156 | static void map_v4v6_address(const char *, char *); |
157 | static void map_v4v6_hostent(struct hostent *, char **, char *); |
158 | static void addrsort(char **, int, res_state); |
159 | |
160 | void dns_service(void); |
161 | #undef dn_skipname |
162 | int dn_skipname(const u_char *, const u_char *); |
163 | |
164 | #ifdef YP |
165 | static struct hostent *_yp_hostent(char *, int, struct getnamaddr *); |
166 | #endif |
167 | |
168 | static struct hostent *gethostbyname_internal(const char *, int, res_state, |
169 | struct hostent *, char *, size_t, int *); |
170 | |
171 | static const ns_src default_dns_files[] = { |
172 | { NSSRC_FILES, NS_SUCCESS }, |
173 | { NSSRC_DNS, NS_SUCCESS }, |
174 | { 0, 0 } |
175 | }; |
176 | |
177 | |
178 | #ifdef DEBUG |
179 | static void |
180 | debugprintf(const char *msg, res_state res, ...) |
181 | { |
182 | _DIAGASSERT(msg != NULL); |
183 | |
184 | if (res->options & RES_DEBUG) { |
185 | int save = errno; |
186 | va_list ap; |
187 | |
188 | va_start (ap, res); |
189 | vprintf(msg, ap); |
190 | va_end (ap); |
191 | |
192 | errno = save; |
193 | } |
194 | } |
195 | #else |
196 | # define debugprintf(msg, res, num) /*nada*/ |
197 | #endif |
198 | |
199 | #define BOUNDED_INCR(x) \ |
200 | do { \ |
201 | cp += (x); \ |
202 | if (cp > eom) \ |
203 | goto no_recovery; \ |
204 | } while (/*CONSTCOND*/0) |
205 | |
206 | #define BOUNDS_CHECK(ptr, count) \ |
207 | do { \ |
208 | if ((ptr) + (count) > eom) \ |
209 | goto no_recovery; \ |
210 | } while (/*CONSTCOND*/0) |
211 | |
212 | static struct hostent * |
213 | getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, |
214 | res_state res, struct hostent *hent, char *buf, size_t buflen, int *he) |
215 | { |
216 | const HEADER *hp; |
217 | const u_char *cp; |
218 | int n; |
219 | size_t qlen; |
220 | const u_char *eom, *erdata; |
221 | char *bp, **ap, **hap, *ep; |
222 | int type, class, ancount, qdcount; |
223 | int haveanswer, had_error; |
224 | int toobig = 0; |
225 | char tbuf[MAXDNAME]; |
226 | char **aliases; |
227 | size_t maxaliases; |
228 | char *addr_ptrs[MAXADDRS]; |
229 | const char *tname; |
230 | int (*name_ok)(const char *); |
231 | |
232 | _DIAGASSERT(answer != NULL); |
233 | _DIAGASSERT(qname != NULL); |
234 | |
235 | tname = qname; |
236 | hent->h_name = NULL; |
237 | eom = answer->buf + anslen; |
238 | switch (qtype) { |
239 | case T_A: |
240 | case T_AAAA: |
241 | name_ok = res_hnok; |
242 | break; |
243 | case T_PTR: |
244 | name_ok = res_dnok; |
245 | break; |
246 | default: |
247 | *he = NO_RECOVERY; |
248 | return NULL; /* XXX should be abort(); */ |
249 | } |
250 | |
251 | setup(aliases, maxaliases); |
252 | /* |
253 | * find first satisfactory answer |
254 | */ |
255 | hp = &answer->hdr; |
256 | ancount = ntohs(hp->ancount); |
257 | qdcount = ntohs(hp->qdcount); |
258 | bp = buf; |
259 | ep = buf + buflen; |
260 | cp = answer->buf; |
261 | BOUNDED_INCR(HFIXEDSZ); |
262 | if (qdcount != 1) |
263 | goto no_recovery; |
264 | |
265 | n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); |
266 | if ((n < 0) || !maybe_ok(res, bp, name_ok)) |
267 | goto no_recovery; |
268 | |
269 | BOUNDED_INCR(n + QFIXEDSZ); |
270 | if (qtype == T_A || qtype == T_AAAA) { |
271 | /* res_send() has already verified that the query name is the |
272 | * same as the one we sent; this just gets the expanded name |
273 | * (i.e., with the succeeding search-domain tacked on). |
274 | */ |
275 | n = (int)strlen(bp) + 1; /* for the \0 */ |
276 | if (n >= MAXHOSTNAMELEN) |
277 | goto no_recovery; |
278 | hent->h_name = bp; |
279 | bp += n; |
280 | /* The qname can be abbreviated, but h_name is now absolute. */ |
281 | qname = hent->h_name; |
282 | } |
283 | hent->h_aliases = ap = aliases; |
284 | hent->h_addr_list = hap = addr_ptrs; |
285 | *ap = NULL; |
286 | *hap = NULL; |
287 | haveanswer = 0; |
288 | had_error = 0; |
289 | while (ancount-- > 0 && cp < eom && !had_error) { |
290 | n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); |
291 | if ((n < 0) || !maybe_ok(res, bp, name_ok)) { |
292 | had_error++; |
293 | continue; |
294 | } |
295 | cp += n; /* name */ |
296 | BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); |
297 | type = _getshort(cp); |
298 | cp += INT16SZ; /* type */ |
299 | class = _getshort(cp); |
300 | cp += INT16SZ + INT32SZ; /* class, TTL */ |
301 | n = _getshort(cp); |
302 | cp += INT16SZ; /* len */ |
303 | BOUNDS_CHECK(cp, n); |
304 | erdata = cp + n; |
305 | if (class != C_IN) { |
306 | /* XXX - debug? syslog? */ |
307 | cp += n; |
308 | continue; /* XXX - had_error++ ? */ |
309 | } |
310 | if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { |
311 | n = dn_expand(answer->buf, eom, cp, tbuf, |
312 | (int)sizeof tbuf); |
313 | if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) { |
314 | had_error++; |
315 | continue; |
316 | } |
317 | cp += n; |
318 | if (cp != erdata) |
319 | goto no_recovery; |
320 | /* Store alias. */ |
321 | addalias(ap, bp, aliases, maxaliases); |
322 | n = (int)strlen(bp) + 1; /* for the \0 */ |
323 | if (n >= MAXHOSTNAMELEN) { |
324 | had_error++; |
325 | continue; |
326 | } |
327 | bp += n; |
328 | /* Get canonical name. */ |
329 | n = (int)strlen(tbuf) + 1; /* for the \0 */ |
330 | if (n > ep - bp || n >= MAXHOSTNAMELEN) { |
331 | had_error++; |
332 | continue; |
333 | } |
334 | strlcpy(bp, tbuf, (size_t)(ep - bp)); |
335 | hent->h_name = bp; |
336 | bp += n; |
337 | continue; |
338 | } |
339 | if (qtype == T_PTR && type == T_CNAME) { |
340 | n = dn_expand(answer->buf, eom, cp, tbuf, |
341 | (int)sizeof tbuf); |
342 | if (n < 0 || !maybe_dnok(res, tbuf)) { |
343 | had_error++; |
344 | continue; |
345 | } |
346 | cp += n; |
347 | if (cp != erdata) |
348 | goto no_recovery; |
349 | /* Get canonical name. */ |
350 | n = (int)strlen(tbuf) + 1; /* for the \0 */ |
351 | if (n > ep - bp || n >= MAXHOSTNAMELEN) { |
352 | had_error++; |
353 | continue; |
354 | } |
355 | strlcpy(bp, tbuf, (size_t)(ep - bp)); |
356 | tname = bp; |
357 | bp += n; |
358 | continue; |
359 | } |
360 | if (type != qtype) { |
361 | if (type != T_KEY && type != T_SIG) |
362 | syslog(LOG_NOTICE|LOG_AUTH, |
363 | "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"" , |
364 | qname, p_class(C_IN), p_type(qtype), |
365 | p_type(type)); |
366 | cp += n; |
367 | continue; /* XXX - had_error++ ? */ |
368 | } |
369 | switch (type) { |
370 | case T_PTR: |
371 | if (strcasecmp(tname, bp) != 0) { |
372 | syslog(LOG_NOTICE|LOG_AUTH, |
373 | AskedForGot, qname, bp); |
374 | cp += n; |
375 | continue; /* XXX - had_error++ ? */ |
376 | } |
377 | n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); |
378 | if ((n < 0) || !maybe_hnok(res, bp)) { |
379 | had_error++; |
380 | break; |
381 | } |
382 | #if MULTI_PTRS_ARE_ALIASES |
383 | cp += n; |
384 | if (cp != erdata) |
385 | goto no_recovery; |
386 | if (!haveanswer) |
387 | hent->h_name = bp; |
388 | else |
389 | addalias(ap, bp, aliases, maxaliases); |
390 | if (n != -1) { |
391 | n = (int)strlen(bp) + 1; /* for the \0 */ |
392 | if (n >= MAXHOSTNAMELEN) { |
393 | had_error++; |
394 | break; |
395 | } |
396 | bp += n; |
397 | } |
398 | break; |
399 | #else |
400 | hent->h_name = bp; |
401 | if (res->options & RES_USE_INET6) { |
402 | n = strlen(bp) + 1; /* for the \0 */ |
403 | if (n >= MAXHOSTNAMELEN) { |
404 | had_error++; |
405 | break; |
406 | } |
407 | bp += n; |
408 | map_v4v6_hostent(hent, &bp, ep); |
409 | } |
410 | goto success; |
411 | #endif |
412 | case T_A: |
413 | case T_AAAA: |
414 | if (strcasecmp(hent->h_name, bp) != 0) { |
415 | syslog(LOG_NOTICE|LOG_AUTH, |
416 | AskedForGot, hent->h_name, bp); |
417 | cp += n; |
418 | continue; /* XXX - had_error++ ? */ |
419 | } |
420 | if (n != hent->h_length) { |
421 | cp += n; |
422 | continue; |
423 | } |
424 | if (type == T_AAAA) { |
425 | struct in6_addr in6; |
426 | memcpy(&in6, cp, NS_IN6ADDRSZ); |
427 | if (IN6_IS_ADDR_V4MAPPED(&in6)) { |
428 | cp += n; |
429 | continue; |
430 | } |
431 | } |
432 | if (!haveanswer) { |
433 | int nn; |
434 | |
435 | hent->h_name = bp; |
436 | nn = (int)strlen(bp) + 1; /* for the \0 */ |
437 | bp += nn; |
438 | } |
439 | |
440 | bp += sizeof(align) - |
441 | (size_t)((u_long)bp % sizeof(align)); |
442 | |
443 | if (bp + n >= ep) { |
444 | debugprintf("size (%d) too big\n" , res, n); |
445 | had_error++; |
446 | continue; |
447 | } |
448 | if (hap >= &addr_ptrs[MAXADDRS - 1]) { |
449 | if (!toobig++) { |
450 | debugprintf("Too many addresses (%d)\n" , |
451 | res, MAXADDRS); |
452 | } |
453 | cp += n; |
454 | continue; |
455 | } |
456 | (void)memcpy(*hap++ = bp, cp, (size_t)n); |
457 | bp += n; |
458 | cp += n; |
459 | if (cp != erdata) |
460 | goto no_recovery; |
461 | break; |
462 | default: |
463 | abort(); |
464 | } |
465 | if (!had_error) |
466 | haveanswer++; |
467 | } |
468 | if (haveanswer) { |
469 | *ap = NULL; |
470 | *hap = NULL; |
471 | /* |
472 | * Note: we sort even if host can take only one address |
473 | * in its return structures - should give it the "best" |
474 | * address in that case, not some random one |
475 | */ |
476 | if (res->nsort && haveanswer > 1 && qtype == T_A) |
477 | addrsort(addr_ptrs, haveanswer, res); |
478 | if (!hent->h_name) { |
479 | n = (int)strlen(qname) + 1; /* for the \0 */ |
480 | if (n > ep - bp || n >= MAXHOSTNAMELEN) |
481 | goto no_recovery; |
482 | strlcpy(bp, qname, (size_t)(ep - bp)); |
483 | hent->h_name = bp; |
484 | bp += n; |
485 | } |
486 | if (res->options & RES_USE_INET6) |
487 | map_v4v6_hostent(hent, &bp, ep); |
488 | goto success; |
489 | } |
490 | no_recovery: |
491 | free(aliases); |
492 | *he = NO_RECOVERY; |
493 | return NULL; |
494 | success: |
495 | bp = (char *)ALIGN(bp); |
496 | n = (int)(ap - aliases); |
497 | qlen = (n + 1) * sizeof(*hent->h_aliases); |
498 | if ((size_t)(ep - bp) < qlen) |
499 | goto nospc; |
500 | hent->h_aliases = (void *)bp; |
501 | memcpy(bp, aliases, qlen); |
502 | free(aliases); |
503 | aliases = NULL; |
504 | |
505 | bp += qlen; |
506 | n = (int)(hap - addr_ptrs); |
507 | qlen = (n + 1) * sizeof(*hent->h_addr_list); |
508 | if ((size_t)(ep - bp) < qlen) |
509 | goto nospc; |
510 | hent->h_addr_list = (void *)bp; |
511 | memcpy(bp, addr_ptrs, qlen); |
512 | *he = NETDB_SUCCESS; |
513 | return hent; |
514 | nospc: |
515 | free(aliases); |
516 | errno = ENOSPC; |
517 | *he = NETDB_INTERNAL; |
518 | return NULL; |
519 | } |
520 | |
521 | struct hostent * |
522 | gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen, |
523 | int *he) |
524 | { |
525 | res_state res = __res_get_state(); |
526 | |
527 | if (res == NULL) { |
528 | *he = NETDB_INTERNAL; |
529 | return NULL; |
530 | } |
531 | |
532 | _DIAGASSERT(name != NULL); |
533 | |
534 | if (res->options & RES_USE_INET6) { |
535 | struct hostent *nhp = gethostbyname_internal(name, AF_INET6, |
536 | res, hp, buf, buflen, he); |
537 | if (nhp) { |
538 | __res_put_state(res); |
539 | return nhp; |
540 | } |
541 | } |
542 | hp = gethostbyname_internal(name, AF_INET, res, hp, buf, buflen, he); |
543 | __res_put_state(res); |
544 | return hp; |
545 | } |
546 | |
547 | struct hostent * |
548 | gethostbyname2_r(const char *name, int af, struct hostent *hp, char *buf, |
549 | size_t buflen, int *he) |
550 | { |
551 | res_state res = __res_get_state(); |
552 | |
553 | if (res == NULL) { |
554 | *he = NETDB_INTERNAL; |
555 | return NULL; |
556 | } |
557 | hp = gethostbyname_internal(name, af, res, hp, buf, buflen, he); |
558 | __res_put_state(res); |
559 | return hp; |
560 | } |
561 | |
562 | static struct hostent * |
563 | gethostbyname_internal(const char *name, int af, res_state res, |
564 | struct hostent *hp, char *buf, size_t buflen, int *he) |
565 | { |
566 | const char *cp; |
567 | struct getnamaddr info; |
568 | char hbuf[MAXHOSTNAMELEN]; |
569 | size_t size; |
570 | static const ns_dtab dtab[] = { |
571 | NS_FILES_CB(_hf_gethtbyname, NULL) |
572 | { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */ |
573 | NS_NIS_CB(_yp_gethtbyname, NULL) |
574 | NS_NULL_CB |
575 | }; |
576 | |
577 | _DIAGASSERT(name != NULL); |
578 | |
579 | switch (af) { |
580 | case AF_INET: |
581 | size = NS_INADDRSZ; |
582 | break; |
583 | case AF_INET6: |
584 | size = NS_IN6ADDRSZ; |
585 | break; |
586 | default: |
587 | *he = NETDB_INTERNAL; |
588 | errno = EAFNOSUPPORT; |
589 | return NULL; |
590 | } |
591 | if (buflen < size) |
592 | goto nospc; |
593 | |
594 | hp->h_addrtype = af; |
595 | hp->h_length = (int)size; |
596 | |
597 | /* |
598 | * if there aren't any dots, it could be a user-level alias. |
599 | * this is also done in res_nquery() since we are not the only |
600 | * function that looks up host names. |
601 | */ |
602 | if (!strchr(name, '.') && (cp = res_hostalias(res, name, |
603 | hbuf, sizeof(hbuf)))) |
604 | name = cp; |
605 | |
606 | /* |
607 | * disallow names consisting only of digits/dots, unless |
608 | * they end in a dot. |
609 | */ |
610 | if (isdigit((u_char) name[0])) |
611 | for (cp = name;; ++cp) { |
612 | if (!*cp) { |
613 | if (*--cp == '.') |
614 | break; |
615 | /* |
616 | * All-numeric, no dot at the end. |
617 | * Fake up a hostent as if we'd actually |
618 | * done a lookup. |
619 | */ |
620 | goto fake; |
621 | } |
622 | if (!isdigit((u_char) *cp) && *cp != '.') |
623 | break; |
624 | } |
625 | if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) || |
626 | name[0] == ':') |
627 | for (cp = name;; ++cp) { |
628 | if (!*cp) { |
629 | if (*--cp == '.') |
630 | break; |
631 | /* |
632 | * All-IPv6-legal, no dot at the end. |
633 | * Fake up a hostent as if we'd actually |
634 | * done a lookup. |
635 | */ |
636 | goto fake; |
637 | } |
638 | if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.') |
639 | break; |
640 | } |
641 | |
642 | *he = NETDB_INTERNAL; |
643 | info.hp = hp; |
644 | info.buf = buf; |
645 | info.buflen = buflen; |
646 | info.he = he; |
647 | if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyname" , |
648 | default_dns_files, name, strlen(name), af) != NS_SUCCESS) |
649 | return NULL; |
650 | *he = NETDB_SUCCESS; |
651 | return hp; |
652 | nospc: |
653 | *he = NETDB_INTERNAL; |
654 | errno = ENOSPC; |
655 | return NULL; |
656 | fake: |
657 | HENT_ARRAY(hp->h_addr_list, 1, buf, buflen); |
658 | HENT_ARRAY(hp->h_aliases, 0, buf, buflen); |
659 | |
660 | hp->h_aliases[0] = NULL; |
661 | if (size > buflen) |
662 | goto nospc; |
663 | |
664 | if (inet_pton(af, name, buf) <= 0) { |
665 | *he = HOST_NOT_FOUND; |
666 | return NULL; |
667 | } |
668 | hp->h_addr_list[0] = buf; |
669 | hp->h_addr_list[1] = NULL; |
670 | buf += size; |
671 | buflen -= size; |
672 | HENT_SCOPY(hp->h_name, name, buf, buflen); |
673 | if (res->options & RES_USE_INET6) |
674 | map_v4v6_hostent(hp, &buf, buf + buflen); |
675 | *he = NETDB_SUCCESS; |
676 | return hp; |
677 | } |
678 | |
679 | struct hostent * |
680 | gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp, |
681 | char *buf, size_t buflen, int *he) |
682 | { |
683 | const u_char *uaddr = (const u_char *)addr; |
684 | socklen_t size; |
685 | struct getnamaddr info; |
686 | static const ns_dtab dtab[] = { |
687 | NS_FILES_CB(_hf_gethtbyaddr, NULL) |
688 | { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */ |
689 | NS_NIS_CB(_yp_gethtbyaddr, NULL) |
690 | NS_NULL_CB |
691 | }; |
692 | |
693 | _DIAGASSERT(addr != NULL); |
694 | |
695 | if (af == AF_INET6 && len == NS_IN6ADDRSZ && |
696 | (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) || |
697 | IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) { |
698 | *he = HOST_NOT_FOUND; |
699 | return NULL; |
700 | } |
701 | if (af == AF_INET6 && len == NS_IN6ADDRSZ && |
702 | (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)addr) || |
703 | IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)addr))) { |
704 | /* Unmap. */ |
705 | uaddr += NS_IN6ADDRSZ - NS_INADDRSZ; |
706 | addr = uaddr; |
707 | af = AF_INET; |
708 | len = NS_INADDRSZ; |
709 | } |
710 | switch (af) { |
711 | case AF_INET: |
712 | size = NS_INADDRSZ; |
713 | break; |
714 | case AF_INET6: |
715 | size = NS_IN6ADDRSZ; |
716 | break; |
717 | default: |
718 | errno = EAFNOSUPPORT; |
719 | *he = NETDB_INTERNAL; |
720 | return NULL; |
721 | } |
722 | if (size != len) { |
723 | errno = EINVAL; |
724 | *he = NETDB_INTERNAL; |
725 | return NULL; |
726 | } |
727 | info.hp = hp; |
728 | info.buf = buf; |
729 | info.buflen = buflen; |
730 | info.he = he; |
731 | *he = NETDB_INTERNAL; |
732 | if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyaddr" , |
733 | default_dns_files, uaddr, len, af) != NS_SUCCESS) |
734 | return NULL; |
735 | *he = NETDB_SUCCESS; |
736 | return hp; |
737 | } |
738 | |
739 | struct hostent * |
740 | gethostent_r(FILE *hf, struct hostent *hent, char *buf, size_t buflen, int *he) |
741 | { |
742 | char *p, *name; |
743 | char *cp, **q; |
744 | int af, len; |
745 | size_t anum; |
746 | char **aliases; |
747 | size_t maxaliases; |
748 | struct in6_addr host_addr; |
749 | |
750 | if (hf == NULL) { |
751 | *he = NETDB_INTERNAL; |
752 | errno = EINVAL; |
753 | return NULL; |
754 | } |
755 | p = NULL; |
756 | setup(aliases, maxaliases); |
757 | for (;;) { |
758 | free(p); |
759 | p = fparseln(hf, NULL, NULL, NULL, FPARSELN_UNESCALL); |
760 | if (p == NULL) { |
761 | free(aliases); |
762 | *he = HOST_NOT_FOUND; |
763 | return NULL; |
764 | } |
765 | if (!(cp = strpbrk(p, " \t" ))) |
766 | continue; |
767 | *cp++ = '\0'; |
768 | if (inet_pton(AF_INET6, p, &host_addr) > 0) { |
769 | af = AF_INET6; |
770 | len = NS_IN6ADDRSZ; |
771 | } else { |
772 | if (inet_pton(AF_INET, p, &host_addr) <= 0) |
773 | continue; |
774 | |
775 | res_state res = __res_get_state(); |
776 | if (res == NULL) |
777 | goto nospc; |
778 | if (res->options & RES_USE_INET6) { |
779 | map_v4v6_address(buf, buf); |
780 | af = AF_INET6; |
781 | len = NS_IN6ADDRSZ; |
782 | } else { |
783 | af = AF_INET; |
784 | len = NS_INADDRSZ; |
785 | } |
786 | __res_put_state(res); |
787 | } |
788 | |
789 | /* if this is not something we're looking for, skip it. */ |
790 | if (hent->h_addrtype != 0 && hent->h_addrtype != af) |
791 | continue; |
792 | if (hent->h_length != 0 && hent->h_length != len) |
793 | continue; |
794 | |
795 | while (*cp == ' ' || *cp == '\t') |
796 | cp++; |
797 | if ((cp = strpbrk(name = cp, " \t" )) != NULL) |
798 | *cp++ = '\0'; |
799 | q = aliases; |
800 | while (cp && *cp) { |
801 | if (*cp == ' ' || *cp == '\t') { |
802 | cp++; |
803 | continue; |
804 | } |
805 | addalias(q, cp, aliases, maxaliases); |
806 | if ((cp = strpbrk(cp, " \t" )) != NULL) |
807 | *cp++ = '\0'; |
808 | } |
809 | break; |
810 | } |
811 | hent->h_length = len; |
812 | hent->h_addrtype = af; |
813 | HENT_ARRAY(hent->h_addr_list, 1, buf, buflen); |
814 | anum = (size_t)(q - aliases); |
815 | HENT_ARRAY(hent->h_aliases, anum, buf, buflen); |
816 | HENT_COPY(hent->h_addr_list[0], &host_addr, hent->h_length, buf, |
817 | buflen); |
818 | hent->h_addr_list[1] = NULL; |
819 | |
820 | HENT_SCOPY(hent->h_name, name, buf, buflen); |
821 | for (size_t i = 0; i < anum; i++) |
822 | HENT_SCOPY(hent->h_aliases[i], aliases[i], buf, buflen); |
823 | hent->h_aliases[anum] = NULL; |
824 | |
825 | *he = NETDB_SUCCESS; |
826 | free(p); |
827 | free(aliases); |
828 | return hent; |
829 | nospc: |
830 | free(p); |
831 | free(aliases); |
832 | errno = ENOSPC; |
833 | *he = NETDB_INTERNAL; |
834 | return NULL; |
835 | } |
836 | |
837 | static void |
838 | map_v4v6_address(const char *src, char *dst) |
839 | { |
840 | u_char *p = (u_char *)dst; |
841 | char tmp[NS_INADDRSZ]; |
842 | int i; |
843 | |
844 | _DIAGASSERT(src != NULL); |
845 | _DIAGASSERT(dst != NULL); |
846 | |
847 | /* Stash a temporary copy so our caller can update in place. */ |
848 | (void)memcpy(tmp, src, NS_INADDRSZ); |
849 | /* Mark this ipv6 addr as a mapped ipv4. */ |
850 | for (i = 0; i < 10; i++) |
851 | *p++ = 0x00; |
852 | *p++ = 0xff; |
853 | *p++ = 0xff; |
854 | /* Retrieve the saved copy and we're done. */ |
855 | (void)memcpy(p, tmp, NS_INADDRSZ); |
856 | } |
857 | |
858 | static void |
859 | map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) |
860 | { |
861 | char **ap; |
862 | |
863 | _DIAGASSERT(hp != NULL); |
864 | _DIAGASSERT(bpp != NULL); |
865 | _DIAGASSERT(ep != NULL); |
866 | |
867 | if (hp->h_addrtype != AF_INET || hp->h_length != NS_INADDRSZ) |
868 | return; |
869 | hp->h_addrtype = AF_INET6; |
870 | hp->h_length = NS_IN6ADDRSZ; |
871 | for (ap = hp->h_addr_list; *ap; ap++) { |
872 | int i = (int)(sizeof(align) - |
873 | (size_t)((u_long)*bpp % sizeof(align))); |
874 | |
875 | if (ep - *bpp < (i + NS_IN6ADDRSZ)) { |
876 | /* Out of memory. Truncate address list here. XXX */ |
877 | *ap = NULL; |
878 | return; |
879 | } |
880 | *bpp += i; |
881 | map_v4v6_address(*ap, *bpp); |
882 | *ap = *bpp; |
883 | *bpp += NS_IN6ADDRSZ; |
884 | } |
885 | } |
886 | |
887 | static void |
888 | addrsort(char **ap, int num, res_state res) |
889 | { |
890 | int i, j; |
891 | char **p; |
892 | short aval[MAXADDRS]; |
893 | int needsort = 0; |
894 | |
895 | _DIAGASSERT(ap != NULL); |
896 | |
897 | p = ap; |
898 | for (i = 0; i < num; i++, p++) { |
899 | for (j = 0 ; (unsigned)j < res->nsort; j++) |
900 | if (res->sort_list[j].addr.s_addr == |
901 | (((struct in_addr *)(void *)(*p))->s_addr & |
902 | res->sort_list[j].mask)) |
903 | break; |
904 | aval[i] = j; |
905 | if (needsort == 0 && i > 0 && j < aval[i-1]) |
906 | needsort = i; |
907 | } |
908 | if (!needsort) |
909 | return; |
910 | |
911 | while (needsort < num) { |
912 | for (j = needsort - 1; j >= 0; j--) { |
913 | if (aval[j] > aval[j+1]) { |
914 | char *hp; |
915 | |
916 | i = aval[j]; |
917 | aval[j] = aval[j+1]; |
918 | aval[j+1] = i; |
919 | |
920 | hp = ap[j]; |
921 | ap[j] = ap[j+1]; |
922 | ap[j+1] = hp; |
923 | } else |
924 | break; |
925 | } |
926 | needsort++; |
927 | } |
928 | } |
929 | |
930 | |
931 | /*ARGSUSED*/ |
932 | int |
933 | _dns_gethtbyname(void *rv, void *cb_data, va_list ap) |
934 | { |
935 | querybuf *buf; |
936 | int n, type; |
937 | struct hostent *hp; |
938 | const char *name; |
939 | res_state res; |
940 | struct getnamaddr *info = rv; |
941 | |
942 | _DIAGASSERT(rv != NULL); |
943 | |
944 | name = va_arg(ap, char *); |
945 | /* NOSTRICT skip string len */(void)va_arg(ap, int); |
946 | info->hp->h_addrtype = va_arg(ap, int); |
947 | |
948 | switch (info->hp->h_addrtype) { |
949 | case AF_INET: |
950 | info->hp->h_length = NS_INADDRSZ; |
951 | type = T_A; |
952 | break; |
953 | case AF_INET6: |
954 | info->hp->h_length = NS_IN6ADDRSZ; |
955 | type = T_AAAA; |
956 | break; |
957 | default: |
958 | return NS_UNAVAIL; |
959 | } |
960 | buf = malloc(sizeof(*buf)); |
961 | if (buf == NULL) { |
962 | *info->he = NETDB_INTERNAL; |
963 | return NS_NOTFOUND; |
964 | } |
965 | res = __res_get_state(); |
966 | if (res == NULL) { |
967 | free(buf); |
968 | *info->he = NETDB_INTERNAL; |
969 | return NS_NOTFOUND; |
970 | } |
971 | n = res_nsearch(res, name, C_IN, type, buf->buf, (int)sizeof(buf->buf)); |
972 | if (n < 0) { |
973 | free(buf); |
974 | debugprintf("res_nsearch failed (%d)\n" , res, n); |
975 | __res_put_state(res); |
976 | return NS_NOTFOUND; |
977 | } |
978 | hp = getanswer(buf, n, name, type, res, info->hp, info->buf, |
979 | info->buflen, info->he); |
980 | free(buf); |
981 | __res_put_state(res); |
982 | if (hp == NULL) |
983 | switch (*info->he) { |
984 | case HOST_NOT_FOUND: |
985 | return NS_NOTFOUND; |
986 | case TRY_AGAIN: |
987 | return NS_TRYAGAIN; |
988 | default: |
989 | return NS_UNAVAIL; |
990 | } |
991 | return NS_SUCCESS; |
992 | } |
993 | |
994 | /*ARGSUSED*/ |
995 | int |
996 | _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap) |
997 | { |
998 | char qbuf[MAXDNAME + 1], *qp, *ep; |
999 | int n; |
1000 | querybuf *buf; |
1001 | struct hostent *hp; |
1002 | const unsigned char *uaddr; |
1003 | int advance; |
1004 | res_state res; |
1005 | char *bf; |
1006 | size_t blen; |
1007 | struct getnamaddr *info = rv; |
1008 | |
1009 | _DIAGASSERT(rv != NULL); |
1010 | |
1011 | uaddr = va_arg(ap, unsigned char *); |
1012 | info->hp->h_length = va_arg(ap, int); |
1013 | info->hp->h_addrtype = va_arg(ap, int); |
1014 | |
1015 | switch (info->hp->h_addrtype) { |
1016 | case AF_INET: |
1017 | (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa" , |
1018 | (uaddr[3] & 0xff), (uaddr[2] & 0xff), |
1019 | (uaddr[1] & 0xff), (uaddr[0] & 0xff)); |
1020 | break; |
1021 | |
1022 | case AF_INET6: |
1023 | qp = qbuf; |
1024 | ep = qbuf + sizeof(qbuf) - 1; |
1025 | for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) { |
1026 | advance = snprintf(qp, (size_t)(ep - qp), "%x.%x." , |
1027 | uaddr[n] & 0xf, |
1028 | ((unsigned int)uaddr[n] >> 4) & 0xf); |
1029 | if (advance > 0 && qp + advance < ep) |
1030 | qp += advance; |
1031 | else |
1032 | goto norecovery; |
1033 | } |
1034 | if (strlcat(qbuf, "ip6.arpa" , sizeof(qbuf)) >= sizeof(qbuf)) |
1035 | goto norecovery; |
1036 | break; |
1037 | default: |
1038 | goto norecovery; |
1039 | } |
1040 | |
1041 | buf = malloc(sizeof(*buf)); |
1042 | if (buf == NULL) { |
1043 | goto nospc; |
1044 | } |
1045 | res = __res_get_state(); |
1046 | if (res == NULL) { |
1047 | free(buf); |
1048 | goto nospc; |
1049 | } |
1050 | n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf)); |
1051 | if (n < 0) { |
1052 | free(buf); |
1053 | debugprintf("res_nquery failed (%d)\n" , res, n); |
1054 | __res_put_state(res); |
1055 | *info->he = HOST_NOT_FOUND; |
1056 | return NS_NOTFOUND; |
1057 | } |
1058 | hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf, |
1059 | info->buflen, info->he); |
1060 | free(buf); |
1061 | if (hp == NULL) { |
1062 | __res_put_state(res); |
1063 | switch (*info->he) { |
1064 | case HOST_NOT_FOUND: |
1065 | return NS_NOTFOUND; |
1066 | case TRY_AGAIN: |
1067 | return NS_TRYAGAIN; |
1068 | default: |
1069 | return NS_UNAVAIL; |
1070 | } |
1071 | } |
1072 | |
1073 | bf = (void *)(hp->h_addr_list + 2); |
1074 | blen = (size_t)(bf - info->buf); |
1075 | if (blen + info->hp->h_length > info->buflen) |
1076 | goto nospc; |
1077 | hp->h_addr_list[0] = bf; |
1078 | hp->h_addr_list[1] = NULL; |
1079 | (void)memcpy(bf, uaddr, (size_t)info->hp->h_length); |
1080 | if (info->hp->h_addrtype == AF_INET && (res->options & RES_USE_INET6)) { |
1081 | if (blen + NS_IN6ADDRSZ > info->buflen) { |
1082 | __res_put_state(res); |
1083 | goto nospc; |
1084 | } |
1085 | map_v4v6_address(bf, bf); |
1086 | hp->h_addrtype = AF_INET6; |
1087 | hp->h_length = NS_IN6ADDRSZ; |
1088 | } |
1089 | |
1090 | __res_put_state(res); |
1091 | *info->he = NETDB_SUCCESS; |
1092 | return NS_SUCCESS; |
1093 | nospc: |
1094 | *info->he = NETDB_INTERNAL; |
1095 | return NS_UNAVAIL; |
1096 | norecovery: |
1097 | *info->he = NO_RECOVERY; |
1098 | return NS_UNAVAIL; |
1099 | } |
1100 | |
1101 | #ifdef YP |
1102 | /*ARGSUSED*/ |
1103 | static struct hostent * |
1104 | _yp_hostent(char *line, int af, struct getnamaddr *info) |
1105 | { |
1106 | struct in6_addr host_addrs[MAXADDRS]; |
1107 | char **aliases; |
1108 | size_t maxaliases; |
1109 | char *p = line; |
1110 | char *cp, **q, *ptr; |
1111 | size_t len, anum, i; |
1112 | int addrok; |
1113 | int more; |
1114 | size_t naddrs; |
1115 | struct hostent *hp = info->hp; |
1116 | |
1117 | _DIAGASSERT(line != NULL); |
1118 | |
1119 | hp->h_name = NULL; |
1120 | hp->h_addrtype = af; |
1121 | switch (af) { |
1122 | case AF_INET: |
1123 | hp->h_length = NS_INADDRSZ; |
1124 | break; |
1125 | case AF_INET6: |
1126 | hp->h_length = NS_IN6ADDRSZ; |
1127 | break; |
1128 | default: |
1129 | return NULL; |
1130 | } |
1131 | setup(aliases, maxaliases); |
1132 | naddrs = 0; |
1133 | q = aliases; |
1134 | |
1135 | nextline: |
1136 | /* check for host_addrs overflow */ |
1137 | if (naddrs >= __arraycount(host_addrs)) |
1138 | goto done; |
1139 | |
1140 | more = 0; |
1141 | cp = strpbrk(p, " \t" ); |
1142 | if (cp == NULL) |
1143 | goto done; |
1144 | *cp++ = '\0'; |
1145 | |
1146 | /* p has should have an address */ |
1147 | addrok = inet_pton(af, p, &host_addrs[naddrs]); |
1148 | if (addrok != 1) { |
1149 | /* skip to the next line */ |
1150 | while (cp && *cp) { |
1151 | if (*cp == '\n') { |
1152 | cp++; |
1153 | goto nextline; |
1154 | } |
1155 | cp++; |
1156 | } |
1157 | goto done; |
1158 | } |
1159 | naddrs++; |
1160 | |
1161 | while (*cp == ' ' || *cp == '\t') |
1162 | cp++; |
1163 | p = cp; |
1164 | cp = strpbrk(p, " \t\n" ); |
1165 | if (cp != NULL) { |
1166 | if (*cp == '\n') |
1167 | more = 1; |
1168 | *cp++ = '\0'; |
1169 | } |
1170 | if (!hp->h_name) |
1171 | hp->h_name = p; |
1172 | else if (strcmp(hp->h_name, p) == 0) |
1173 | ; |
1174 | else |
1175 | addalias(q, p, aliases, maxaliases); |
1176 | p = cp; |
1177 | if (more) |
1178 | goto nextline; |
1179 | |
1180 | while (cp && *cp) { |
1181 | if (*cp == ' ' || *cp == '\t') { |
1182 | cp++; |
1183 | continue; |
1184 | } |
1185 | if (*cp == '\n') { |
1186 | cp++; |
1187 | goto nextline; |
1188 | } |
1189 | addalias(q, cp, aliases, maxaliases); |
1190 | cp = strpbrk(cp, " \t" ); |
1191 | if (cp != NULL) |
1192 | *cp++ = '\0'; |
1193 | } |
1194 | |
1195 | done: |
1196 | if (hp->h_name == NULL) { |
1197 | free(aliases); |
1198 | return NULL; |
1199 | } |
1200 | |
1201 | ptr = info->buf; |
1202 | len = info->buflen; |
1203 | |
1204 | anum = (size_t)(q - aliases); |
1205 | HENT_ARRAY(hp->h_addr_list, naddrs, ptr, len); |
1206 | HENT_ARRAY(hp->h_aliases, anum, ptr, len); |
1207 | |
1208 | for (i = 0; i < naddrs; i++) |
1209 | HENT_COPY(hp->h_addr_list[i], &host_addrs[i], hp->h_length, |
1210 | ptr, len); |
1211 | hp->h_addr_list[naddrs] = NULL; |
1212 | |
1213 | HENT_SCOPY(hp->h_name, hp->h_name, ptr, len); |
1214 | |
1215 | for (i = 0; i < anum; i++) |
1216 | HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len); |
1217 | hp->h_aliases[anum] = NULL; |
1218 | free(aliases); |
1219 | |
1220 | return hp; |
1221 | nospc: |
1222 | free(aliases); |
1223 | *info->he = NETDB_INTERNAL; |
1224 | errno = ENOSPC; |
1225 | return NULL; |
1226 | } |
1227 | |
1228 | /*ARGSUSED*/ |
1229 | int |
1230 | _yp_gethtbyaddr(void *rv, void *cb_data, va_list ap) |
1231 | { |
1232 | struct hostent *hp = NULL; |
1233 | char *ypcurrent; |
1234 | int ypcurrentlen, r; |
1235 | char name[INET6_ADDRSTRLEN]; /* XXX enough? */ |
1236 | const unsigned char *uaddr; |
1237 | int af; |
1238 | const char *map; |
1239 | struct getnamaddr *info = rv; |
1240 | |
1241 | _DIAGASSERT(rv != NULL); |
1242 | |
1243 | uaddr = va_arg(ap, unsigned char *); |
1244 | /* NOSTRICT skip len */(void)va_arg(ap, int); |
1245 | af = va_arg(ap, int); |
1246 | |
1247 | if (!__ypdomain) { |
1248 | if (_yp_check(&__ypdomain) == 0) |
1249 | return NS_UNAVAIL; |
1250 | } |
1251 | /* |
1252 | * XXX unfortunately, we cannot support IPv6 extended scoped address |
1253 | * notation here. gethostbyaddr() is not scope-aware. too bad. |
1254 | */ |
1255 | if (inet_ntop(af, uaddr, name, (socklen_t)sizeof(name)) == NULL) |
1256 | return NS_UNAVAIL; |
1257 | switch (af) { |
1258 | case AF_INET: |
1259 | map = "hosts.byaddr" ; |
1260 | break; |
1261 | default: |
1262 | map = "ipnodes.byaddr" ; |
1263 | break; |
1264 | } |
1265 | ypcurrent = NULL; |
1266 | r = yp_match(__ypdomain, map, name, |
1267 | (int)strlen(name), &ypcurrent, &ypcurrentlen); |
1268 | if (r == 0) |
1269 | hp = _yp_hostent(ypcurrent, af, info); |
1270 | else |
1271 | hp = NULL; |
1272 | free(ypcurrent); |
1273 | if (hp == NULL) { |
1274 | *info->he = HOST_NOT_FOUND; |
1275 | return NS_NOTFOUND; |
1276 | } |
1277 | return NS_SUCCESS; |
1278 | } |
1279 | |
1280 | /*ARGSUSED*/ |
1281 | int |
1282 | _yp_gethtbyname(void *rv, void *cb_data, va_list ap) |
1283 | { |
1284 | struct hostent *hp; |
1285 | char *ypcurrent; |
1286 | int ypcurrentlen, r; |
1287 | const char *name; |
1288 | int af; |
1289 | const char *map; |
1290 | struct getnamaddr *info = rv; |
1291 | |
1292 | _DIAGASSERT(rv != NULL); |
1293 | |
1294 | name = va_arg(ap, char *); |
1295 | /* NOSTRICT skip string len */(void)va_arg(ap, int); |
1296 | af = va_arg(ap, int); |
1297 | |
1298 | if (!__ypdomain) { |
1299 | if (_yp_check(&__ypdomain) == 0) |
1300 | return NS_UNAVAIL; |
1301 | } |
1302 | switch (af) { |
1303 | case AF_INET: |
1304 | map = "hosts.byname" ; |
1305 | break; |
1306 | default: |
1307 | map = "ipnodes.byname" ; |
1308 | break; |
1309 | } |
1310 | ypcurrent = NULL; |
1311 | r = yp_match(__ypdomain, map, name, |
1312 | (int)strlen(name), &ypcurrent, &ypcurrentlen); |
1313 | if (r == 0) |
1314 | hp = _yp_hostent(ypcurrent, af, info); |
1315 | else |
1316 | hp = NULL; |
1317 | free(ypcurrent); |
1318 | if (hp == NULL) { |
1319 | *info->he = HOST_NOT_FOUND; |
1320 | return NS_NOTFOUND; |
1321 | } |
1322 | return NS_SUCCESS; |
1323 | } |
1324 | #endif |
1325 | |
1326 | /* |
1327 | * Non-reentrant versions. |
1328 | */ |
1329 | FILE *_h_file; |
1330 | static struct hostent h_ent; |
1331 | static char h_buf[16384]; |
1332 | |
1333 | struct hostent * |
1334 | gethostbyaddr(const void *addr, socklen_t len, int af) { |
1335 | return gethostbyaddr_r(addr, len, af, &h_ent, h_buf, sizeof(h_buf), |
1336 | &h_errno); |
1337 | } |
1338 | |
1339 | struct hostent * |
1340 | gethostbyname(const char *name) { |
1341 | return gethostbyname_r(name, &h_ent, h_buf, sizeof(h_buf), &h_errno); |
1342 | } |
1343 | |
1344 | struct hostent * |
1345 | gethostbyname2(const char *name, int af) { |
1346 | return gethostbyname2_r(name, af, &h_ent, h_buf, sizeof(h_buf), |
1347 | &h_errno); |
1348 | } |
1349 | |
1350 | struct hostent * |
1351 | gethostent(void) |
1352 | { |
1353 | if (_h_file == NULL) { |
1354 | sethostent_r(&_h_file); |
1355 | if (_h_file == NULL) { |
1356 | h_errno = NETDB_INTERNAL; |
1357 | return NULL; |
1358 | } |
1359 | } |
1360 | memset(&h_ent, 0, sizeof(h_ent)); |
1361 | return gethostent_r(_h_file, &h_ent, h_buf, sizeof(h_buf), &h_errno); |
1362 | } |
1363 | |
1364 | |