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