xref: /openbsd-src/lib/libc/asr/gethostnamadr_async.c (revision 262cf3f83cdbd553ad7b1911d8d86c0037d66365)
1 /*	$OpenBSD: gethostnamadr_async.c,v 1.8 2012/09/06 15:05:16 eric Exp $	*/
2 /*
3  * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <arpa/nameser.h>
23 
24 #include <err.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #ifdef YP
30 #include <rpc/rpc.h>
31 #include <rpcsvc/yp.h>
32 #include <rpcsvc/ypclnt.h>
33 #include "ypinternal.h"
34 #endif
35 
36 #include "asr.h"
37 #include "asr_private.h"
38 
39 
40 #define MAXALIASES	16
41 #define MAXADDRS	16
42 
43 #define HOSTENT_PTR(h) ((char**)(((char*)h) + sizeof (*h)))
44 #define HOSTENT_POS(h)  HOSTENT_PTR(h)[0]
45 #define HOSTENT_STOP(h)	HOSTENT_PTR(h)[1]
46 #define HOSTENT_LEFT(h) (HOSTENT_STOP(h) - HOSTENT_POS(h))
47 
48 ssize_t addr_as_fqdn(const char *, int, char *, size_t);
49 
50 static int gethostnamadr_async_run(struct async *, struct async_res *);
51 static struct hostent *hostent_alloc(int);
52 static int hostent_set_cname(struct hostent *, const char *, int);
53 static int hostent_add_alias(struct hostent *, const char *, int);
54 static int hostent_add_addr(struct hostent *, const void *, int);
55 static struct hostent *hostent_file_match(FILE *, int, int, const char *, int);
56 static struct hostent *hostent_from_packet(int, int, char *, size_t);
57 #ifdef YP
58 static struct hostent *_yp_gethostnamadr(int, const void *);
59 static struct hostent *hostent_from_yp(int, char *);
60 #endif
61 
62 struct async *
63 gethostbyname_async(const char *name, struct asr *asr)
64 {
65 	return gethostbyname2_async(name, AF_INET, asr);
66 }
67 
68 struct async *
69 gethostbyname2_async(const char *name, int af, struct asr *asr)
70 {
71 	struct asr_ctx	*ac;
72 	struct async	*as;
73 
74 	/* the original segfaults */
75 	if (name == NULL) {
76 		errno = EINVAL;
77 		return (NULL);
78 	}
79 
80 	ac = asr_use_resolver(asr);
81 	if ((as = async_new(ac, ASR_GETHOSTBYNAME)) == NULL)
82 		goto abort; /* errno set */
83 	as->as_run = gethostnamadr_async_run;
84 
85 	as->as.hostnamadr.family = af;
86 	if (af == AF_INET)
87 		as->as.hostnamadr.addrlen = INADDRSZ;
88 	else if (af == AF_INET6)
89 		as->as.hostnamadr.addrlen = IN6ADDRSZ;
90 	as->as.hostnamadr.name = strdup(name);
91 	if (as->as.hostnamadr.name == NULL)
92 		goto abort; /* errno set */
93 
94 	asr_ctx_unref(ac);
95 	return (as);
96 
97     abort:
98 	if (as)
99 		async_free(as);
100 	asr_ctx_unref(ac);
101 	return (NULL);
102 }
103 
104 struct async *
105 gethostbyaddr_async(const void *addr, socklen_t len, int af, struct asr *asr)
106 {
107 	struct asr_ctx	*ac;
108 	struct async	*as;
109 
110 	ac = asr_use_resolver(asr);
111 	as = gethostbyaddr_async_ctx(addr, len, af, ac);
112 	asr_ctx_unref(ac);
113 
114 	return (as);
115 }
116 
117 struct async *
118 gethostbyaddr_async_ctx(const void *addr, socklen_t len, int af,
119     struct asr_ctx *ac)
120 {
121 	struct async	*as;
122 
123 	if ((as = async_new(ac, ASR_GETHOSTBYADDR)) == NULL)
124 		goto abort; /* errno set */
125 	as->as_run = gethostnamadr_async_run;
126 
127 	as->as.hostnamadr.family = af;
128 	as->as.hostnamadr.addrlen = len;
129 	if (len > 0)
130 		memmove(as->as.hostnamadr.addr, addr, (len > 16) ? 16 : len);
131 
132 	return (as);
133 
134     abort:
135 	if (as)
136 		async_free(as);
137 	return (NULL);
138 }
139 
140 static int
141 gethostnamadr_async_run(struct async *as, struct async_res *ar)
142 {
143 	int	r, type;
144 	FILE	*f;
145 	char	dname[MAXDNAME], *data;
146 
147     next:
148 	switch(as->as_state) {
149 
150 	case ASR_STATE_INIT:
151 
152 		if (as->as.hostnamadr.family != AF_INET &&
153 		    as->as.hostnamadr.family != AF_INET6) {
154 			ar->ar_h_errno = NETDB_INTERNAL;
155 			ar->ar_errno = EAFNOSUPPORT;
156 			async_set_state(as, ASR_STATE_HALT);
157 			break;
158 		}
159 
160 		if ((as->as.hostnamadr.family == AF_INET &&
161 		     as->as.hostnamadr.addrlen != INADDRSZ) ||
162 		    (as->as.hostnamadr.family == AF_INET6 &&
163 		     as->as.hostnamadr.addrlen != IN6ADDRSZ)) {
164 			ar->ar_h_errno = NETDB_INTERNAL;
165 			ar->ar_errno = EINVAL;
166 			async_set_state(as, ASR_STATE_HALT);
167 			break;
168 		}
169 
170 		if (as->as_type == ASR_GETHOSTBYNAME)
171 			async_set_state(as, ASR_STATE_NEXT_DOMAIN);
172 		else
173 			async_set_state(as, ASR_STATE_NEXT_DB);
174 		break;
175 
176 	case ASR_STATE_NEXT_DOMAIN:
177 
178 		r = asr_iter_domain(as, as->as.hostnamadr.name, dname, sizeof(dname));
179 		if (r == -1) {
180 			async_set_state(as, ASR_STATE_NOT_FOUND);
181 			break;
182 		}
183 
184 		if (as->as.hostnamadr.dname)
185 			free(as->as.hostnamadr.dname);
186 		if ((as->as.hostnamadr.dname = strdup(dname)) == NULL) {
187 			ar->ar_h_errno = NETDB_INTERNAL;
188 			ar->ar_errno = errno;
189 			async_set_state(as, ASR_STATE_HALT);
190 		}
191 
192 		as->as_db_idx = 0;
193 		async_set_state(as, ASR_STATE_NEXT_DB);
194 		break;
195 
196 	case ASR_STATE_NEXT_DB:
197 
198 		if (asr_iter_db(as) == -1) {
199 			if (as->as_type == ASR_GETHOSTBYNAME)
200 				async_set_state(as, ASR_STATE_NEXT_DOMAIN);
201 			else
202 				async_set_state(as, ASR_STATE_NOT_FOUND);
203 			break;
204 		}
205 
206 		switch(AS_DB(as)) {
207 
208 		case ASR_DB_DNS:
209 
210 			/* Create a subquery to do the DNS lookup */
211 
212 			if (as->as_type == ASR_GETHOSTBYNAME) {
213 				type = (as->as.hostnamadr.family == AF_INET) ?
214 				    T_A : T_AAAA;
215 				as->as.hostnamadr.subq = res_query_async_ctx(
216 				    as->as.hostnamadr.dname,
217 				    C_IN, type, NULL, 0, as->as_ctx);
218 			} else {
219 				addr_as_fqdn(as->as.hostnamadr.addr,
220 				    as->as.hostnamadr.family,
221 				    dname, sizeof(dname));
222 				as->as.hostnamadr.subq = res_query_async_ctx(
223 				    dname, C_IN, T_PTR, NULL, 0, as->as_ctx);
224 			}
225 
226 			if (as->as.hostnamadr.subq == NULL) {
227 				ar->ar_errno = errno;
228 				ar->ar_h_errno = NETDB_INTERNAL;
229 				async_set_state(as, ASR_STATE_HALT);
230 				break;
231 			}
232 
233 			async_set_state(as, ASR_STATE_SUBQUERY);
234 			break;
235 
236 		case ASR_DB_FILE:
237 
238 			/* Try to find a match in the host file */
239 
240 			if ((f = fopen(as->as_ctx->ac_hostfile, "r")) == NULL)
241 				break;
242 
243 			if (as->as_type == ASR_GETHOSTBYNAME)
244 				data = as->as.hostnamadr.dname;
245 			else
246 				data = as->as.hostnamadr.addr;
247 
248 			ar->ar_hostent = hostent_file_match(f, as->as_type,
249 			    as->as.hostnamadr.family, data,
250 			    as->as.hostnamadr.addrlen);
251 
252 			fclose(f);
253 
254 			if (ar->ar_hostent == NULL) {
255 				if (errno) {
256 					ar->ar_errno = errno;
257 					ar->ar_h_errno = NETDB_INTERNAL;
258 					async_set_state(as, ASR_STATE_HALT);
259 				}
260 				/* otherwise not found */
261 				break;
262 			}
263 
264 			ar->ar_h_errno = NETDB_SUCCESS;
265 			async_set_state(as, ASR_STATE_HALT);
266 			break;
267 #ifdef YP
268 		case ASR_DB_YP:
269 			/* IPv4 only */
270 			if (as->as.hostnamadr.family != AF_INET)
271 				break;
272 			if (as->as_type == ASR_GETHOSTBYNAME)
273 				data = as->as.hostnamadr.dname;
274 			else
275 				data = as->as.hostnamadr.addr;
276 			ar->ar_hostent = _yp_gethostnamadr(as->as_type, data);
277 			if (ar->ar_hostent == NULL) {
278 				if (errno) {
279 					ar->ar_errno = errno;
280 					ar->ar_h_errno = NETDB_INTERNAL;
281 					async_set_state(as, ASR_STATE_HALT);
282 				}
283 				/* otherwise not found */
284 				break;
285 			}
286 
287 			ar->ar_h_errno = NETDB_SUCCESS;
288 			async_set_state(as, ASR_STATE_HALT);
289 			break;
290 #endif
291 		}
292 		break;
293 
294 	case ASR_STATE_SUBQUERY:
295 
296 		/* Run the DNS subquery. */
297 
298 		if ((r = async_run(as->as.hostnamadr.subq, ar)) == ASYNC_COND)
299 			return (ASYNC_COND);
300 
301 		/* Done. */
302 		as->as.hostnamadr.subq = NULL;
303 
304 		if (ar->ar_datalen == -1) {
305 			async_set_state(as, ASR_STATE_NEXT_DB);
306 			break;
307 		}
308 
309 		/* If we got a packet but no anwser, use the next DB. */
310 		if (ar->ar_count == 0) {
311 			free(ar->ar_data);
312 			async_set_state(as, ASR_STATE_NEXT_DB);
313 			break;
314 		}
315 
316 		/* Read the hostent from the packet. */
317 
318 		ar->ar_hostent = hostent_from_packet(as->as_type,
319 		    as->as.hostnamadr.family, ar->ar_data, ar->ar_datalen);
320 		free(ar->ar_data);
321 
322 		if (ar->ar_hostent == NULL) {
323 			ar->ar_errno = errno;
324 			ar->ar_h_errno = NETDB_INTERNAL;
325 			async_set_state(as, ASR_STATE_HALT);
326 			break;
327 		}
328 
329 		if (as->as_type == ASR_GETHOSTBYADDR) {
330 			if (hostent_add_addr(ar->ar_hostent,
331 			    as->as.hostnamadr.addr,
332 			    as->as.hostnamadr.addrlen) == -1) {
333 				free(ar->ar_hostent);
334 				ar->ar_errno = errno;
335 				ar->ar_h_errno = NETDB_INTERNAL;
336 				async_set_state(as, ASR_STATE_HALT);
337 				break;
338 			}
339 		}
340 
341 		/*
342 		 * No address found in the dns packet. The blocking version
343 		 * reports this as an error.
344 		 */
345 		if (as->as_type == ASR_GETHOSTBYNAME &&
346 		    ar->ar_hostent->h_addr_list[0] == NULL) {
347 			free(ar->ar_hostent);
348 			async_set_state(as, ASR_STATE_NEXT_DB);
349 			break;
350 		}
351 
352 		ar->ar_h_errno = NETDB_SUCCESS;
353 		async_set_state(as, ASR_STATE_HALT);
354 		break;
355 
356 	case ASR_STATE_NOT_FOUND:
357 		ar->ar_errno = 0;
358 		ar->ar_h_errno = HOST_NOT_FOUND;
359 		async_set_state(as, ASR_STATE_HALT);
360 		break;
361 
362 	case ASR_STATE_HALT:
363 		if (ar->ar_h_errno)
364 			ar->ar_hostent = NULL;
365 		else
366 			ar->ar_errno = 0;
367 		return (ASYNC_DONE);
368 
369 	default:
370 		ar->ar_errno = EOPNOTSUPP;
371 		ar->ar_h_errno = NETDB_INTERNAL;
372 		ar->ar_gai_errno = EAI_SYSTEM;
373 		async_set_state(as, ASR_STATE_HALT);
374                 break;
375 	}
376 	goto next;
377 }
378 
379 /*
380  * Lookup the first matching entry in the hostfile, either by address or by
381  * name depending on reqtype, and build a hostent from the line.
382  */
383 static struct hostent *
384 hostent_file_match(FILE *f, int reqtype, int family, const char *data, int datalen)
385 {
386 	char	*tokens[MAXTOKEN], addr[16];
387 	struct	 hostent *h;
388 	int	 n, i;
389 
390 	for(;;) {
391 		n = asr_parse_namedb_line(f, tokens, MAXTOKEN);
392 		if (n == -1) {
393 			errno = 0; /* ignore errors reading the file */
394 			return (NULL);
395 		}
396 
397 		if (reqtype == ASR_GETHOSTBYNAME) {
398 			for (i = 1; i < n; i++) {
399 				if (strcasecmp(data, tokens[i]))
400 					continue;
401 				if (inet_pton(family, tokens[0], addr) == 1)
402 					goto found;
403 			}
404 		} else {
405 			if (inet_pton(family, tokens[0], addr) == 1)
406 				if (memcmp(addr, data, datalen) == 0)
407 					goto found;
408 		}
409 	}
410 
411 found:
412 	if ((h = hostent_alloc(family)) == NULL)
413 		return (NULL);
414 	if (hostent_set_cname(h, tokens[1], 0) == -1)
415 		goto fail;
416 	for (i = 2; i < n; i ++)
417 		if (hostent_add_alias(h, tokens[i], 0) == -1)
418 			goto fail;
419 	if (hostent_add_addr(h, addr, h->h_length) == -1)
420 		goto fail;
421 	return (h);
422 fail:
423 	free(h);
424 	return (NULL);
425 }
426 
427 /*
428  * Fill the hostent from the given DNS packet.
429  */
430 static struct hostent *
431 hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen)
432 {
433 	struct hostent	*h;
434 	struct packed	 p;
435 	struct header	 hdr;
436 	struct query	 q;
437 	struct rr	 rr;
438 
439 	if ((h = hostent_alloc(family)) == NULL)
440 		return (NULL);
441 
442 	packed_init(&p, pkt, pktlen);
443 	unpack_header(&p, &hdr);
444 	for(; hdr.qdcount; hdr.qdcount--)
445 		unpack_query(&p, &q);
446 	for(; hdr.ancount; hdr.ancount--) {
447 		unpack_rr(&p, &rr);
448 		if (rr.rr_class != C_IN)
449 			continue;
450 		switch (rr.rr_type) {
451 
452 		case T_CNAME:
453 			if (reqtype == ASR_GETHOSTBYNAME) {
454 				if (hostent_add_alias(h, rr.rr_dname, 1) == -1)
455 					goto fail;
456 			} else {
457 				if (hostent_set_cname(h, rr.rr_dname, 1) == -1)
458 					goto fail;
459 			}
460 			break;
461 
462 		case T_PTR:
463 			if (reqtype != ASR_GETHOSTBYADDR)
464 				break;
465 			if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1)
466 				goto fail;
467 			/* XXX See if we need MULTI_PTRS_ARE_ALIASES */
468 			break;
469 
470 		case T_A:
471 			if (reqtype != ASR_GETHOSTBYNAME)
472 				break;
473 			if (family != AF_INET)
474 				break;
475 			if (hostent_set_cname(h, rr.rr_dname, 1) == -1)
476 				goto fail;
477 			if (hostent_add_addr(h, &rr.rr.in_a.addr, 4) == -1)
478 				goto fail;
479 			break;
480 
481 		case T_AAAA:
482 			if (reqtype != ASR_GETHOSTBYNAME)
483 				break;
484 			if (family != AF_INET6)
485 				break;
486 			if (hostent_set_cname(h, rr.rr_dname, 1) == -1)
487 				goto fail;
488 			if (hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16) == -1)
489 				goto fail;
490 			break;
491 		}
492 	}
493 
494 	return (h);
495 fail:
496 	free(h);
497 	return (NULL);
498 }
499 
500 static struct hostent *
501 hostent_alloc(int family)
502 {
503 	struct hostent	*h;
504 	size_t		 alloc;
505 
506 	alloc = sizeof(*h) + (2 + MAXALIASES + MAXADDRS) * sizeof(char*) + 1024;
507 	if ((h = calloc(1, alloc)) == NULL)
508 		return (NULL);
509 
510 	h->h_addrtype = family;
511 	h->h_length = (family == AF_INET) ? 4 : 16;
512 	h->h_aliases = HOSTENT_PTR(h) + 2;
513 	h->h_addr_list = h->h_aliases + MAXALIASES;
514 
515 	HOSTENT_STOP(h) = (char*)(h) + alloc;
516 	HOSTENT_POS(h) = (char*)(h->h_addr_list + MAXADDRS);
517 
518 	return (h);
519 }
520 
521 static int
522 hostent_set_cname(struct hostent *h, const char *name, int isdname)
523 {
524 	char	buf[MAXDNAME];
525 
526 	if (h->h_name)
527 		return (0);
528 
529 	if (isdname) {
530 		asr_strdname(name, buf, sizeof buf);
531 		buf[strlen(buf) - 1] = '\0';
532 		name = buf;
533 	}
534 	if (strlen(name) + 1 >= HOSTENT_LEFT(h))
535 		return (1);
536 
537 	strlcpy(HOSTENT_POS(h), name, HOSTENT_LEFT(h));
538 	h->h_name = HOSTENT_POS(h);
539 	HOSTENT_POS(h) += strlen(name) + 1;
540 
541 	return (0);
542 }
543 
544 static int
545 hostent_add_alias(struct hostent *h, const char *name, int isdname)
546 {
547 	char	buf[MAXDNAME];
548 	size_t	i;
549 
550 	for (i = 0; i < MAXALIASES - 1; i++)
551 		if (h->h_aliases[i] == NULL)
552 			break;
553 	if (i == MAXALIASES - 1)
554 		return (0);
555 
556 	if (isdname) {
557 		asr_strdname(name, buf, sizeof buf);
558 		buf[strlen(buf)-1] = '\0';
559 		name = buf;
560 	}
561 	if (strlen(name) + 1 >= HOSTENT_LEFT(h))
562 		return (1);
563 
564 	strlcpy(HOSTENT_POS(h), name, HOSTENT_LEFT(h));
565 	h->h_aliases[i] = HOSTENT_POS(h);
566 	HOSTENT_POS(h) += strlen(name) + 1;
567 
568 	return (0);
569 }
570 
571 static int
572 hostent_add_addr(struct hostent *h, const void *addr, int size)
573 {
574 	int	i;
575 
576 	for (i = 0; i < MAXADDRS - 1; i++)
577 		if (h->h_addr_list[i] == NULL)
578 			break;
579 	if (i == MAXADDRS - 1)
580 		return (0);
581 
582 	if (size >= HOSTENT_LEFT(h))
583 		return (1);
584 
585 	memmove(HOSTENT_POS(h), addr, size);
586 	h->h_addr_list[i] = HOSTENT_POS(h);
587 	HOSTENT_POS(h) += size;
588 
589 	return (0);
590 }
591 
592 ssize_t
593 addr_as_fqdn(const char *addr, int family, char *dst, size_t max)
594 {
595 	const struct in6_addr	*in6_addr;
596 	in_addr_t		 in_addr;
597 
598 	switch (family) {
599 	case AF_INET:
600 		in_addr = ntohl(*((const in_addr_t *)addr));
601 		snprintf(dst, max,
602 		    "%d.%d.%d.%d.in-addr.arpa.",
603 		    in_addr & 0xff,
604 		    (in_addr >> 8) & 0xff,
605 		    (in_addr >> 16) & 0xff,
606 		    (in_addr >> 24) & 0xff);
607 		break;
608 	case AF_INET6:
609 		in6_addr = (const struct in6_addr *)addr;
610 		snprintf(dst, max,
611 		    "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
612 		    "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
613 		    "ip6.arpa.",
614 		    in6_addr->s6_addr[15] & 0xf,
615 		    (in6_addr->s6_addr[15] >> 4) & 0xf,
616 		    in6_addr->s6_addr[14] & 0xf,
617 		    (in6_addr->s6_addr[14] >> 4) & 0xf,
618 		    in6_addr->s6_addr[13] & 0xf,
619 		    (in6_addr->s6_addr[13] >> 4) & 0xf,
620 		    in6_addr->s6_addr[12] & 0xf,
621 		    (in6_addr->s6_addr[12] >> 4) & 0xf,
622 		    in6_addr->s6_addr[11] & 0xf,
623 		    (in6_addr->s6_addr[11] >> 4) & 0xf,
624 		    in6_addr->s6_addr[10] & 0xf,
625 		    (in6_addr->s6_addr[10] >> 4) & 0xf,
626 		    in6_addr->s6_addr[9] & 0xf,
627 		    (in6_addr->s6_addr[9] >> 4) & 0xf,
628 		    in6_addr->s6_addr[8] & 0xf,
629 		    (in6_addr->s6_addr[8] >> 4) & 0xf,
630 		    in6_addr->s6_addr[7] & 0xf,
631 		    (in6_addr->s6_addr[7] >> 4) & 0xf,
632 		    in6_addr->s6_addr[6] & 0xf,
633 		    (in6_addr->s6_addr[6] >> 4) & 0xf,
634 		    in6_addr->s6_addr[5] & 0xf,
635 		    (in6_addr->s6_addr[5] >> 4) & 0xf,
636 		    in6_addr->s6_addr[4] & 0xf,
637 		    (in6_addr->s6_addr[4] >> 4) & 0xf,
638 		    in6_addr->s6_addr[3] & 0xf,
639 		    (in6_addr->s6_addr[3] >> 4) & 0xf,
640 		    in6_addr->s6_addr[2] & 0xf,
641 		    (in6_addr->s6_addr[2] >> 4) & 0xf,
642 		    in6_addr->s6_addr[1] & 0xf,
643 		    (in6_addr->s6_addr[1] >> 4) & 0xf,
644 		    in6_addr->s6_addr[0] & 0xf,
645 		    (in6_addr->s6_addr[0] >> 4) & 0xf);
646 		break;
647 	default:
648 		return (-1);
649 	}
650 	return (0);
651 }
652 
653 #ifdef YP
654 static struct hostent *
655 _yp_gethostnamadr(int type, const void *data)
656 {
657 	static char	*domain = NULL;
658 	struct hostent	*h = NULL;
659 	const char	*name;
660 	char		 buf[MAXHOSTNAMELEN];
661 	char		*res = NULL;
662 	int		 r, len;
663 
664 	if (!domain && _yp_check(&domain) == 0) {
665 		errno = 0; /* ignore yp_bind errors */
666 		return (NULL);
667 	}
668 
669 	if (type == ASR_GETHOSTBYNAME) {
670 		name = data;
671 		len = strlen(name);
672 		r = yp_match(domain, "hosts.byname", name, len, &res, &len);
673 	}
674 	else {
675 		if (inet_ntop(AF_INET, data, buf, sizeof buf) == NULL)
676 			return (NULL);
677 		len = strlen(buf);
678 		r = yp_match(domain, "hosts.byaddr", buf, len, &res, &len);
679 	}
680 	if (r == 0) {
681 		h = hostent_from_yp(AF_INET, res);
682 	} else {
683 		errno = 0; /* ignore error if not found */
684 	}
685 	if (res)
686 		free(res);
687 	return (h);
688 }
689 
690 static int
691 strsplit(char *line, char **tokens, int ntokens)
692 {
693 	int	ntok;
694 	char	*cp, **tp;
695 
696 	for(cp = line, tp = tokens, ntok = 0;
697 	    ntok < ntokens && (*tp = strsep(&cp, " \t")) != NULL; )
698 		if (**tp != '\0') {
699 			tp++;
700 			ntok++;
701 		}
702 
703 	return (ntok);
704 }
705 
706 static struct hostent *
707 hostent_from_yp(int family, char *line)
708 {
709 	struct hostent	*h;
710 	char		*next, *tokens[10], addr[IN6ADDRSZ];
711 	int		 i, ntok;
712 
713 	if ((h = hostent_alloc(family)) == NULL)
714 		return (NULL);
715 
716 	for(next = line; line; line = next) {
717 		if ((next = strchr(line, '\n'))) {
718 			*next = '\0';
719 			next += 1;
720 		}
721 		ntok = strsplit(line, tokens, 10);
722 		if (ntok < 2)
723 			continue;
724 		if (inet_pton(family, tokens[0], addr) == 1)
725 			hostent_add_addr(h, addr, family == AF_INET ?
726 			    INADDRSZ : IN6ADDRSZ);
727 		i = 2;
728 		if (!h->h_name)
729 			hostent_set_cname(h, tokens[1], 0);
730 		else if (strcmp(h->h_name, tokens[1]))
731 			i = 1;
732 		for (; i < ntok; i++)
733 			hostent_add_alias(h, tokens[i], 0);
734 	}
735 
736 	if (h->h_name == NULL) {
737 		free(h);
738 		return (NULL);
739 	}
740 
741 	return (h);
742 }
743 #endif
744