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