1 /*-
2  * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD: stable/10/tools/regression/lib/libc/nss/test-gethostby.c 291759 2015-12-04 09:18:12Z ngie $");
30 
31 #include <arpa/inet.h>
32 #include <sys/socket.h>
33 #include <sys/types.h>
34 #include <netinet/in.h>
35 #include <assert.h>
36 #include <errno.h>
37 #include <netdb.h>
38 #include <resolv.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <stringlist.h>
43 #include <unistd.h>
44 #include "testutil.h"
45 
46 #ifndef min
47 #define min(a,b) (((a)<(b))?(a):(b))
48 #endif
49 
50 enum test_methods {
51 	TEST_GETHOSTBYNAME2,
52 	TEST_GETHOSTBYADDR,
53 	TEST_GETHOSTBYNAME2_GETADDRINFO,
54 	TEST_GETHOSTBYADDR_GETNAMEINFO,
55 	TEST_BUILD_SNAPSHOT,
56 	TEST_BUILD_ADDR_SNAPSHOT
57 };
58 
59 static int use_ipnode_functions = 0;
60 static int use_ipv6_mapping = 0;
61 static int ipnode_flags = 0;
62 static int debug = 0;
63 static int af_type = AF_INET;
64 static enum test_methods method = TEST_BUILD_SNAPSHOT;
65 
66 DECLARE_TEST_DATA(hostent)
67 DECLARE_TEST_FILE_SNAPSHOT(hostent)
68 DECLARE_1PASS_TEST(hostent)
69 DECLARE_2PASS_TEST(hostent)
70 
71 /* These stubs will use gethostby***() or getipnodeby***() functions,
72  * depending on the use_ipnode_functions global variable value */
73 static struct hostent *__gethostbyname2(const char *, int);
74 static struct hostent *__gethostbyaddr(const void *, socklen_t, int);
75 static void __freehostent(struct hostent *);
76 
77 static void clone_hostent(struct hostent *, struct hostent const *);
78 static int compare_hostent(struct hostent *, struct hostent *, void *);
79 static void dump_hostent(struct hostent *);
80 static void free_hostent(struct hostent *);
81 
82 static int is_hostent_equal(struct hostent *, struct addrinfo *);
83 
84 static void sdump_hostent(struct hostent *, char *, size_t);
85 static int hostent_read_hostlist_func(struct hostent *, char *);
86 static int hostent_read_snapshot_addr(char *, unsigned char *, size_t);
87 static int hostent_read_snapshot_func(struct hostent *, char *);
88 
89 static int hostent_test_correctness(struct hostent *, void *);
90 static int hostent_test_gethostbyaddr(struct hostent *, void *);
91 static int hostent_test_getaddrinfo_eq(struct hostent *, void *);
92 static int hostent_test_getnameinfo_eq(struct hostent *, void *);
93 
94 static void usage(void)  __attribute__((__noreturn__));
95 
96 IMPLEMENT_TEST_DATA(hostent)
IMPLEMENT_TEST_FILE_SNAPSHOT(hostent)97 IMPLEMENT_TEST_FILE_SNAPSHOT(hostent)
98 IMPLEMENT_1PASS_TEST(hostent)
99 IMPLEMENT_2PASS_TEST(hostent)
100 
101 static struct hostent *
102 __gethostbyname2(const char *name, int af)
103 {
104 	struct hostent *he;
105 	int error;
106 
107 	if (use_ipnode_functions == 0)
108 		he = gethostbyname2(name, af);
109 	else {
110 		error = 0;
111 		he = getipnodebyname(name, af, ipnode_flags, &error);
112 		if (he == NULL);
113 			errno = error;
114 	}
115 
116 	return (he);
117 }
118 
119 static struct hostent *
__gethostbyaddr(const void * addr,socklen_t len,int af)120 __gethostbyaddr(const void *addr, socklen_t len, int af)
121 {
122 	struct hostent *he;
123 	int error;
124 
125 	if (use_ipnode_functions == 0)
126 		he = gethostbyaddr(addr, len, af);
127 	else {
128 		error = 0;
129 		he = getipnodebyaddr(addr, len, af, &error);
130 		if (he == NULL)
131 			errno = error;
132 	}
133 
134 	return (he);
135 }
136 
137 static void
__freehostent(struct hostent * he)138 __freehostent(struct hostent *he)
139 {
140 	/* NOTE: checking for he != NULL - just in case */
141 	if ((use_ipnode_functions != 0) && (he != NULL))
142 		freehostent(he);
143 }
144 
145 static void
clone_hostent(struct hostent * dest,struct hostent const * src)146 clone_hostent(struct hostent *dest, struct hostent const *src)
147 {
148 	assert(dest != NULL);
149 	assert(src != NULL);
150 
151 	char **cp;
152 	int aliases_num;
153 	int addrs_num;
154 	size_t offset;
155 
156 	memset(dest, 0, sizeof(struct hostent));
157 
158 	if (src->h_name != NULL) {
159 		dest->h_name = strdup(src->h_name);
160 		assert(dest->h_name != NULL);
161 	}
162 
163 	dest->h_addrtype = src->h_addrtype;
164 	dest->h_length = src->h_length;
165 
166 	if (src->h_aliases != NULL) {
167 		aliases_num = 0;
168 		for (cp = src->h_aliases; *cp; ++cp)
169 			++aliases_num;
170 
171 		dest->h_aliases = (char **)malloc((aliases_num + 1) *
172 			(sizeof(char *)));
173 		assert(dest->h_aliases != NULL);
174 		memset(dest->h_aliases, 0, (aliases_num + 1) *
175 			(sizeof(char *)));
176 
177 		for (cp = src->h_aliases; *cp; ++cp) {
178 			dest->h_aliases[cp - src->h_aliases] = strdup(*cp);
179 			assert(dest->h_aliases[cp - src->h_aliases] != NULL);
180 		}
181 	}
182 
183 	if (src->h_addr_list != NULL) {
184 		addrs_num = 0;
185 		for (cp = src->h_addr_list; *cp; ++cp)
186 			++addrs_num;
187 
188 		dest->h_addr_list = (char **)malloc((addrs_num + 1) *
189 			(sizeof(char *)));
190 		assert(dest->h_addr_list != NULL);
191 		memset(dest->h_addr_list, 0, (addrs_num + 1) *
192 			(sizeof(char *)));
193 
194 		for (cp = src->h_addr_list; *cp; ++cp) {
195 			offset = cp - src->h_addr_list;
196 			dest->h_addr_list[offset] =
197 				(char *)malloc(src->h_length);
198 			assert(dest->h_addr_list[offset] != NULL);
199 			memcpy(dest->h_addr_list[offset],
200 				src->h_addr_list[offset], src->h_length);
201 		}
202 	}
203 }
204 
205 static void
free_hostent(struct hostent * ht)206 free_hostent(struct hostent *ht)
207 {
208 	char **cp;
209 
210 	assert(ht != NULL);
211 
212 	free(ht->h_name);
213 
214 	if (ht->h_aliases != NULL) {
215 		for (cp = ht->h_aliases; *cp; ++cp)
216 			free(*cp);
217 		free(ht->h_aliases);
218 	}
219 
220 	if  (ht->h_addr_list != NULL) {
221 		for (cp = ht->h_addr_list; *cp; ++cp)
222 			free(*cp);
223 		free(ht->h_addr_list);
224 	}
225 }
226 
227 static  int
compare_hostent(struct hostent * ht1,struct hostent * ht2,void * mdata)228 compare_hostent(struct hostent *ht1, struct hostent *ht2, void *mdata)
229 {
230 	char **c1, **c2, **ct, **cb;
231 	int b;
232 
233 	if (ht1 == ht2)
234 		return 0;
235 
236 	if ((ht1 == NULL) || (ht2 == NULL))
237 		goto errfin;
238 
239 	if ((ht1->h_name == NULL) || (ht2->h_name == NULL))
240 		goto errfin;
241 
242 	if ((ht1->h_addrtype != ht2->h_addrtype) ||
243 		(ht1->h_length != ht2->h_length) ||
244 		(strcmp(ht1->h_name, ht2->h_name) != 0))
245 			goto errfin;
246 
247 	c1 = ht1->h_aliases;
248 	c2 = ht2->h_aliases;
249 
250 	if (((ht1->h_aliases == NULL) || (ht2->h_aliases == NULL)) &&
251 		(ht1->h_aliases != ht2->h_aliases))
252 		goto errfin;
253 
254 	if ((c1 != NULL) && (c2 != NULL)) {
255 		cb = c1;
256 		for (;*c1; ++c1) {
257 			b = 0;
258 			for (ct = c2; *ct; ++ct) {
259 				if (strcmp(*c1, *ct) == 0) {
260 					b = 1;
261 					break;
262 				}
263 			}
264 			if (b == 0) {
265 				if (debug)
266 					printf("h1 aliases item can't be "\
267 					    "found in h2 aliases\n");
268 				goto errfin;
269 			}
270 		}
271 
272 		c1 = cb;
273 		for (;*c2; ++c2) {
274 			b = 0;
275 			for (ct = c1; *ct; ++ct) {
276 				if (strcmp(*c2, *ct) == 0) {
277 					b = 1;
278 					break;
279 				}
280 			}
281 			if (b == 0) {
282 				if (debug)
283 					printf("h2 aliases item can't be "\
284 					    " found in h1 aliases\n");
285 				goto errfin;
286 			}
287 		}
288 	}
289 
290 	c1 = ht1->h_addr_list;
291 	c2 = ht2->h_addr_list;
292 
293 	if (((ht1->h_addr_list == NULL) || (ht2->h_addr_list== NULL)) &&
294 		(ht1->h_addr_list != ht2->h_addr_list))
295 		goto errfin;
296 
297 	if ((c1 != NULL) && (c2 != NULL)) {
298 		cb = c1;
299 		for (;*c1; ++c1) {
300 			b = 0;
301 			for (ct = c2; *ct; ++ct) {
302 				if (memcmp(*c1, *ct, ht1->h_length) == 0) {
303 					b = 1;
304 					break;
305 				}
306 			}
307 			if (b == 0) {
308 				if (debug)
309 					printf("h1 addresses item can't be "\
310 					    "found in h2 addresses\n");
311 				goto errfin;
312 			}
313 		}
314 
315 		c1 = cb;
316 		for (;*c2; ++c2) {
317 			b = 0;
318 			for (ct = c1; *ct; ++ct) {
319 				if (memcmp(*c2, *ct, ht1->h_length) == 0) {
320 					b = 1;
321 					break;
322 				}
323 			}
324 			if (b == 0) {
325 				if (debug)
326 					printf("h2 addresses item can't be "\
327 					    "found in h1 addresses\n");
328 				goto errfin;
329 			}
330 		}
331 	}
332 
333 	return 0;
334 
335 errfin:
336 	if ((debug) && (mdata == NULL)) {
337 		printf("following structures are not equal:\n");
338 		dump_hostent(ht1);
339 		dump_hostent(ht2);
340 	}
341 
342 	return (-1);
343 }
344 
345 static int
check_addrinfo_for_name(struct addrinfo * ai,char const * name)346 check_addrinfo_for_name(struct addrinfo *ai, char const *name)
347 {
348 	struct addrinfo *ai2;
349 
350 	for (ai2 = ai; ai2 != NULL; ai2 = ai2->ai_next) {
351 		if (strcmp(ai2->ai_canonname, name) == 0)
352 			return (0);
353 	}
354 
355 	return (-1);
356 }
357 
358 static int
check_addrinfo_for_addr(struct addrinfo * ai,char const * addr,socklen_t addrlen,int af)359 check_addrinfo_for_addr(struct addrinfo *ai, char const *addr,
360 	socklen_t addrlen, int af)
361 {
362 	struct addrinfo *ai2;
363 
364 	for (ai2 = ai; ai2 != NULL; ai2 = ai2->ai_next) {
365 		if (af != ai2->ai_family)
366 			continue;
367 
368 		switch (af) {
369 			case AF_INET:
370 				if (memcmp(addr,
371 				    (void *)&((struct sockaddr_in *)ai2->ai_addr)->sin_addr,
372 				    min(addrlen, ai2->ai_addrlen)) == 0)
373 				    return (0);
374 			break;
375 			case AF_INET6:
376 				if (memcmp(addr,
377 				    (void *)&((struct sockaddr_in6 *)ai2->ai_addr)->sin6_addr,
378 				    min(addrlen, ai2->ai_addrlen)) == 0)
379 				    return (0);
380 			break;
381 			default:
382 			break;
383 		}
384 	}
385 
386 	return (-1);
387 }
388 
389 static int
is_hostent_equal(struct hostent * he,struct addrinfo * ai)390 is_hostent_equal(struct hostent *he, struct addrinfo *ai)
391 {
392 	char **cp;
393 	int rv;
394 
395 	if (debug)
396 		printf("checking equality of he and ai\n");
397 
398 	rv = check_addrinfo_for_name(ai, he->h_name);
399 	if (rv != 0) {
400 		if (debug)
401 			printf("not equal - he->h_name couldn't be found\n");
402 
403 		return (rv);
404 	}
405 
406 	for (cp = he->h_addr_list; *cp; ++cp) {
407 		rv = check_addrinfo_for_addr(ai, *cp, he->h_length,
408 			he->h_addrtype);
409 		if (rv != 0) {
410 			if (debug)
411 				printf("not equal - one of he->h_addr_list couldn't be found\n");
412 
413 			return (rv);
414 		}
415 	}
416 
417 	if (debug)
418 		printf("equal\n");
419 
420 	return (0);
421 }
422 
423 static void
sdump_hostent(struct hostent * ht,char * buffer,size_t buflen)424 sdump_hostent(struct hostent *ht, char *buffer, size_t buflen)
425 {
426 	char **cp;
427 	size_t i;
428 	int written;
429 
430 	written = snprintf(buffer, buflen, "%s %d %d",
431 		ht->h_name, ht->h_addrtype, ht->h_length);
432 	buffer += written;
433 	if (written > buflen)
434 		return;
435 	buflen -= written;
436 
437 	if (ht->h_aliases != NULL) {
438 		if (*(ht->h_aliases) != NULL) {
439 			for (cp = ht->h_aliases; *cp; ++cp) {
440 				written = snprintf(buffer, buflen, " %s",*cp);
441 				buffer += written;
442 				if (written > buflen)
443 					return;
444 				buflen -= written;
445 
446 				if (buflen == 0)
447 					return;
448 			}
449 		} else {
450 			written = snprintf(buffer, buflen, " noaliases");
451 			buffer += written;
452 			if (written > buflen)
453 				return;
454 			buflen -= written;
455 		}
456 	} else {
457 		written = snprintf(buffer, buflen, " (null)");
458 		buffer += written;
459 		if (written > buflen)
460 			return;
461 		buflen -= written;
462 	}
463 
464 	written = snprintf(buffer, buflen, " : ");
465 	buffer += written;
466 	if (written > buflen)
467 		return;
468 	buflen -= written;
469 
470 	if (ht->h_addr_list != NULL) {
471 		if (*(ht->h_addr_list) != NULL) {
472 			for (cp = ht->h_addr_list; *cp; ++cp) {
473 			    for (i = 0; i < ht->h_length; ++i ) {
474 				written = snprintf(buffer, buflen,
475 				    	i + 1 != ht->h_length ? "%d." : "%d",
476 				    	(unsigned char)(*cp)[i]);
477 				buffer += written;
478 				if (written > buflen)
479 					return;
480 				buflen -= written;
481 
482 				if (buflen == 0)
483 					return;
484 			    }
485 
486 			    if (*(cp + 1) ) {
487 				written = snprintf(buffer, buflen, " ");
488 				buffer += written;
489 				if (written > buflen)
490 				    return;
491 				buflen -= written;
492 			    }
493 			}
494 		} else {
495 			written = snprintf(buffer, buflen, " noaddrs");
496 			buffer += written;
497 			if (written > buflen)
498 				return;
499 			buflen -= written;
500 		}
501 	} else {
502 		written = snprintf(buffer, buflen, " (null)");
503 		buffer += written;
504 		if (written > buflen)
505 			return;
506 		buflen -= written;
507 	}
508 }
509 
510 static int
hostent_read_hostlist_func(struct hostent * he,char * line)511 hostent_read_hostlist_func(struct hostent *he, char *line)
512 {
513 	struct hostent *result;
514 	int rv;
515 
516 	if (debug)
517 		printf("resolving %s: ", line);
518 	result = __gethostbyname2(line, af_type);
519 	if (result != NULL) {
520 		if (debug)
521 			printf("found\n");
522 
523 		rv = hostent_test_correctness(result, NULL);
524 		if (rv != 0) {
525 			__freehostent(result);
526 			return (rv);
527 		}
528 
529 		clone_hostent(he, result);
530 		__freehostent(result);
531 	} else {
532 		if (debug)
533 			printf("not found\n");
534 
535  		memset(he, 0, sizeof(struct hostent));
536 		he->h_name = strdup(line);
537 		assert(he->h_name != NULL);
538 	}
539 	return (0);
540 }
541 
542 static int
hostent_read_snapshot_addr(char * addr,unsigned char * result,size_t len)543 hostent_read_snapshot_addr(char *addr, unsigned char *result, size_t len)
544 {
545 	char *s, *ps, *ts;
546 
547 	ps = addr;
548 	while ( (s = strsep(&ps, ".")) != NULL) {
549 		if (len == 0)
550 			return (-1);
551 
552 		*result = (unsigned char)strtol(s, &ts, 10);
553 		++result;
554 		if (*ts != '\0')
555 			return (-1);
556 
557 		--len;
558 	}
559 	if (len != 0)
560 		return (-1);
561 	else
562 		return (0);
563 }
564 
565 static int
hostent_read_snapshot_func(struct hostent * ht,char * line)566 hostent_read_snapshot_func(struct hostent *ht, char *line)
567 {
568 	StringList *sl1, *sl2;
569 	char *s, *ps, *ts;
570 	int i, rv;
571 
572 	if (debug)
573 		printf("1 line read from snapshot:\n%s\n", line);
574 
575 	rv = 0;
576 	i = 0;
577 	sl1 = sl2 = NULL;
578 	ps = line;
579 	memset(ht, 0, sizeof(struct hostent));
580 	while ( (s = strsep(&ps, " ")) != NULL) {
581 		switch (i) {
582 			case 0:
583 				ht->h_name = strdup(s);
584 				assert(ht->h_name != NULL);
585 			break;
586 
587 			case 1:
588 				ht->h_addrtype = (int)strtol(s, &ts, 10);
589 				if (*ts != '\0')
590 					goto fin;
591 			break;
592 
593 			case 2:
594 				ht->h_length = (int)strtol(s, &ts, 10);
595 				if (*ts != '\0')
596 					goto fin;
597 			break;
598 
599 			case 3:
600 				if (sl1 == NULL) {
601 					if (strcmp(s, "(null)") == 0)
602 						return (0);
603 
604 					sl1 = sl_init();
605 					assert(sl1 != NULL);
606 
607 					if (strcmp(s, "noaliases") != 0) {
608 						ts = strdup(s);
609 						assert(ts != NULL);
610 						sl_add(sl1, ts);
611 					}
612 				} else {
613 					if (strcmp(s, ":") == 0)
614 						++i;
615 					else {
616 						ts = strdup(s);
617 						assert(ts != NULL);
618 						sl_add(sl1, ts);
619 					}
620 				}
621 			break;
622 
623 			case 4:
624 				if (sl2 == NULL) {
625 					if (strcmp(s, "(null)") == 0)
626 						return (0);
627 
628 					sl2 = sl_init();
629 					assert(sl2 != NULL);
630 
631 					if (strcmp(s, "noaddrs") != 0) {
632 					    ts = (char *)malloc(ht->h_length);
633 					    assert(ts != NULL);
634 					    memset(ts, 0, ht->h_length);
635 					    rv = hostent_read_snapshot_addr(s,\
636 						 (unsigned char *)ts, ht->h_length);
637 					    sl_add(sl2, ts);
638 					    if (rv != 0)
639 						    goto fin;
640 					}
641 				} else {
642 				    ts = (char *)malloc(ht->h_length);
643 				    assert(ts != NULL);
644 				    memset(ts, 0, ht->h_length);
645 				    rv = hostent_read_snapshot_addr(s,\
646 					(unsigned char *)ts, ht->h_length);
647 				    sl_add(sl2, ts);
648 				    if (rv != 0)
649 					    goto fin;
650 				}
651 			break;
652 			default:
653 			break;
654 		};
655 
656 		if ((i != 3) && (i != 4))
657 			++i;
658 	}
659 
660 fin:
661 	if (sl1 != NULL) {
662 		sl_add(sl1, NULL);
663 		ht->h_aliases = sl1->sl_str;
664 	}
665 	if (sl2 != NULL) {
666 		sl_add(sl2, NULL);
667 		ht->h_addr_list = sl2->sl_str;
668 	}
669 
670 	if ((i != 4) || (rv != 0)) {
671 		free_hostent(ht);
672 		memset(ht, 0, sizeof(struct hostent));
673 		return (-1);
674 	}
675 
676 	/* NOTE: is it a dirty hack or not? */
677 	free(sl1);
678 	free(sl2);
679 	return (0);
680 }
681 
682 static void
dump_hostent(struct hostent * result)683 dump_hostent(struct hostent *result)
684 {
685 	if (result != NULL) {
686 		char buffer[1024];
687 		sdump_hostent(result, buffer, sizeof(buffer));
688 		printf("%s\n", buffer);
689 	} else
690 		printf("(null)\n");
691 }
692 
693 static int
hostent_test_correctness(struct hostent * ht,void * mdata)694 hostent_test_correctness(struct hostent *ht, void *mdata)
695 {
696 	if (debug) {
697 		printf("testing correctness with the following data:\n");
698 		dump_hostent(ht);
699 	}
700 
701 	if (ht == NULL)
702 		goto errfin;
703 
704 	if (ht->h_name == NULL)
705 		goto errfin;
706 
707 	if (!((ht->h_addrtype >= 0) && (ht->h_addrtype < AF_MAX)))
708 		goto errfin;
709 
710 	if ((ht->h_length != sizeof(struct in_addr)) &&
711 		(ht->h_length != sizeof(struct in6_addr)))
712 		goto errfin;
713 
714 	if (ht->h_aliases == NULL)
715 		goto errfin;
716 
717 	if (ht->h_addr_list == NULL)
718 		goto errfin;
719 
720 	if (debug)
721 		printf("correct\n");
722 
723 	return (0);
724 errfin:
725 	if (debug)
726 		printf("incorrect\n");
727 
728 	return (-1);
729 }
730 
731 static int
hostent_test_gethostbyaddr(struct hostent * he,void * mdata)732 hostent_test_gethostbyaddr(struct hostent *he, void *mdata)
733 {
734 	struct hostent *result;
735 	struct hostent_test_data *addr_test_data;
736 	int rv;
737 
738 	addr_test_data = (struct hostent_test_data *)mdata;
739 
740 	/* We should omit unresolved hostents */
741 	if (he->h_addr_list != NULL) {
742 		char **cp;
743 		for (cp = he->h_addr_list; *cp; ++cp) {
744 			if (debug)
745 			    printf("doing reverse lookup for %s\n", he->h_name);
746 
747 			result = __gethostbyaddr(*cp, he->h_length,
748 			    he->h_addrtype);
749 			if (result == NULL) {
750 				if (debug)
751 				    printf("warning: reverse lookup failed\n");
752 
753 				continue;
754 			}
755 			rv = hostent_test_correctness(result, NULL);
756 			if (rv != 0) {
757 			    __freehostent(result);
758 			    return (rv);
759 			}
760 
761 			if (addr_test_data != NULL)
762 			    TEST_DATA_APPEND(hostent, addr_test_data, result);
763 
764 			__freehostent(result);
765 		}
766 	}
767 
768 	return (0);
769 }
770 
771 static int
hostent_test_getaddrinfo_eq(struct hostent * he,void * mdata)772 hostent_test_getaddrinfo_eq(struct hostent *he, void *mdata)
773 {
774 	struct addrinfo *ai, hints;
775 	int rv;
776 
777 	ai = NULL;
778 	memset(&hints, 0, sizeof(struct addrinfo));
779 	hints.ai_family = af_type;
780 	hints.ai_flags = AI_CANONNAME;
781 
782 	if (debug)
783 		printf("using getaddrinfo() to resolve %s\n", he->h_name);
784 
785 	/* struct hostent *he was not resolved */
786 	if (he->h_addr_list == NULL) {
787 		/* We can be sure that he->h_name is not NULL */
788 		rv = getaddrinfo(he->h_name, NULL, &hints, &ai);
789 		if (rv == 0) {
790 			if (debug)
791 			    printf("not ok - shouldn't have been resolved\n");
792 			return (-1);
793 		}
794 	} else {
795 		rv = getaddrinfo(he->h_name, NULL, &hints, &ai);
796 		if (rv != 0) {
797 			if (debug)
798 			    printf("not ok - should have beed resolved\n");
799 			return (-1);
800 		}
801 
802 		rv = is_hostent_equal(he, ai);
803 		if (rv != 0) {
804 			if (debug)
805 			    printf("not ok - addrinfo and hostent are not equal\n");
806 			return (-1);
807 		}
808 
809 	}
810 
811 	return (0);
812 }
813 
814 static int
hostent_test_getnameinfo_eq(struct hostent * he,void * mdata)815 hostent_test_getnameinfo_eq(struct hostent *he, void *mdata)
816 {
817 	char buffer[NI_MAXHOST];
818 	struct sockaddr_in sin;
819 	struct sockaddr_in6 sin6;
820 	struct sockaddr *saddr;
821 	struct hostent *result;
822 	int rv;
823 
824 	if (he->h_addr_list != NULL) {
825 		char **cp;
826 		for (cp = he->h_addr_list; *cp; ++cp) {
827 			if (debug)
828 			    printf("doing reverse lookup for %s\n", he->h_name);
829 
830 			result = __gethostbyaddr(*cp, he->h_length,
831 			    he->h_addrtype);
832 			if (result != NULL) {
833 				rv = hostent_test_correctness(result, NULL);
834 				if (rv != 0) {
835 				    __freehostent(result);
836 				    return (rv);
837 				}
838 			} else {
839 				if (debug)
840 				    printf("reverse lookup failed\n");
841 			}
842 
843 			switch (he->h_addrtype) {
844 			case AF_INET:
845 				memset(&sin, 0, sizeof(struct sockaddr_in));
846 				sin.sin_len = sizeof(struct sockaddr_in);
847 				sin.sin_family = AF_INET;
848 				memcpy(&sin.sin_addr, *cp, he->h_length);
849 
850 				saddr = (struct sockaddr *)&sin;
851 				break;
852 			case AF_INET6:
853 				memset(&sin6, 0, sizeof(struct sockaddr_in6));
854 				sin6.sin6_len = sizeof(struct sockaddr_in6);
855 				sin6.sin6_family = AF_INET6;
856 				memcpy(&sin6.sin6_addr, *cp, he->h_length);
857 
858 				saddr = (struct sockaddr *)&sin6;
859 				break;
860 			default:
861 				if (debug)
862 					printf("warning: %d family is unsupported\n",
863 						he->h_addrtype);
864 				continue;
865 			}
866 
867 			assert(saddr != NULL);
868 			rv = getnameinfo(saddr, saddr->sa_len, buffer,
869 				sizeof(buffer), NULL, 0, NI_NAMEREQD);
870 
871 			if ((rv != 0) && (result != NULL)) {
872 				if (debug)
873 					printf("not ok - getnameinfo() didn't make the reverse lookup, when it should have (%s)\n",
874 						gai_strerror(rv));
875 				return (rv);
876 			}
877 
878 			if ((rv == 0) && (result == NULL)) {
879 				if (debug)
880 					printf("not ok - getnameinfo() made the reverse lookup, when it shouldn't have\n");
881 				return (rv);
882 			}
883 
884 			if ((rv != 0) && (result == NULL)) {
885 				if (debug)
886 					printf("ok - both getnameinfo() and ***byaddr() failed\n");
887 
888 				continue;
889 			}
890 
891 			if (debug)
892 				printf("comparing %s with %s\n", result->h_name,
893 					buffer);
894 
895 			rv = strcmp(result->h_name, buffer);
896 			__freehostent(result);
897 
898 			if (rv != 0) {
899 				if (debug)
900 					printf("not ok - getnameinfo() and ***byaddr() results are not equal\n");
901 				return (rv);
902 			} else {
903 				if (debug)
904 					printf("ok - getnameinfo() and ***byaddr() results are equal\n");
905 			}
906 		}
907 	}
908 
909 	return (0);
910 }
911 
912 static void
usage(void)913 usage(void)
914 {
915 	(void)fprintf(stderr,
916 	    "Usage: %s -na2i [-o] [-d] [-46] [-mAcM] [-C] [-s <file>] -f <file>\n",
917 	    getprogname());
918 	exit(1);
919 }
920 
921 int
main(int argc,char ** argv)922 main(int argc, char **argv)
923 {
924 	struct hostent_test_data td, td_addr, td_snap;
925 	char *snapshot_file, *hostlist_file;
926 	res_state statp;
927 	int rv;
928 	int c;
929 
930 	if (argc < 2)
931 		usage();
932 
933 	snapshot_file = NULL;
934 	hostlist_file = NULL;
935 	while ((c = getopt(argc, argv, "nad2iod46mAcMs:f:")) != -1)
936 		switch (c) {
937 		case '4':
938 			af_type = AF_INET;
939 			break;
940 		case '6':
941 			af_type = AF_INET6;
942 			break;
943 		case 'M':
944 			af_type = AF_INET6;
945 			use_ipv6_mapping = 1;
946 			ipnode_flags |= AI_V4MAPPED_CFG;
947 			break;
948 		case 'm':
949 			af_type = AF_INET6;
950 			use_ipv6_mapping = 1;
951 			ipnode_flags |= AI_V4MAPPED;
952 			break;
953 		case 'c':
954 			ipnode_flags |= AI_ADDRCONFIG;
955 			break;
956 		case 'A':
957 			ipnode_flags |= AI_ALL;
958 			break;
959 		case 'o':
960 			use_ipnode_functions = 1;
961 			break;
962 		case 'd':
963 			debug = 1;
964 			break;
965 		case 'n':
966 			method = TEST_GETHOSTBYNAME2;
967 			break;
968 		case 'a':
969 			method = TEST_GETHOSTBYADDR;
970 			break;
971 		case '2':
972 			method = TEST_GETHOSTBYNAME2_GETADDRINFO;
973 			break;
974 		case 'i':
975 			method = TEST_GETHOSTBYADDR_GETNAMEINFO;
976 			break;
977 		case 's':
978 			snapshot_file = strdup(optarg);
979 			break;
980 		case 'f':
981 			hostlist_file = strdup(optarg);
982 			break;
983 		default:
984 			usage();
985 		}
986 
987 	if (use_ipnode_functions == 0) {
988 		statp = __res_state();
989 		if ((statp == NULL) || ((statp->options & RES_INIT) == 0 &&
990 			res_ninit(statp) == -1)) {
991 			if (debug)
992 			    printf("error: can't init res_state\n");
993 
994 			free(snapshot_file);
995 			free(hostlist_file);
996 			return (-1);
997 		}
998 
999 		if (use_ipv6_mapping == 0)
1000 			statp->options &= ~RES_USE_INET6;
1001 		else
1002 			statp->options |= RES_USE_INET6;
1003 	}
1004 
1005 	TEST_DATA_INIT(hostent, &td, clone_hostent, free_hostent);
1006 	TEST_DATA_INIT(hostent, &td_addr, clone_hostent, free_hostent);
1007 	TEST_DATA_INIT(hostent, &td_snap, clone_hostent, free_hostent);
1008 
1009 	if (hostlist_file == NULL)
1010 		usage();
1011 
1012 	if (access(hostlist_file, R_OK) != 0) {
1013 		if (debug)
1014 			printf("can't access the hostlist file %s\n",
1015 				hostlist_file);
1016 
1017 		usage();
1018 	}
1019 
1020 	if (debug)
1021 		printf("building host lists from %s\n", hostlist_file);
1022 
1023 	rv = TEST_SNAPSHOT_FILE_READ(hostent, hostlist_file, &td,
1024 		hostent_read_hostlist_func);
1025 	if (rv != 0)
1026 		goto fin;
1027 
1028 	if (snapshot_file != NULL) {
1029 		if (access(snapshot_file, W_OK | R_OK) != 0) {
1030 			if (errno == ENOENT) {
1031 				if (method != TEST_GETHOSTBYADDR)
1032 					method = TEST_BUILD_SNAPSHOT;
1033 				else
1034 					method = TEST_BUILD_ADDR_SNAPSHOT;
1035 			} else {
1036 				if (debug)
1037 				    printf("can't access the snapshot file %s\n",
1038 				    snapshot_file);
1039 
1040 				rv = -1;
1041 				goto fin;
1042 			}
1043 		} else {
1044 			rv = TEST_SNAPSHOT_FILE_READ(hostent, snapshot_file,
1045 				&td_snap, hostent_read_snapshot_func);
1046 			if (rv != 0) {
1047 				if (debug)
1048 					printf("error reading snapshot file\n");
1049 				goto fin;
1050 			}
1051 		}
1052 	}
1053 
1054 	switch (method) {
1055 	case TEST_GETHOSTBYNAME2:
1056 		if (snapshot_file != NULL)
1057 			rv = DO_2PASS_TEST(hostent, &td, &td_snap,
1058 				compare_hostent, NULL);
1059 		break;
1060 	case TEST_GETHOSTBYADDR:
1061 		rv = DO_1PASS_TEST(hostent, &td,
1062 			hostent_test_gethostbyaddr, (void *)&td_addr);
1063 
1064 		if (snapshot_file != NULL)
1065 			rv = DO_2PASS_TEST(hostent, &td_addr, &td_snap,
1066 				compare_hostent, NULL);
1067 		break;
1068 	case TEST_GETHOSTBYNAME2_GETADDRINFO:
1069 		rv = DO_1PASS_TEST(hostent, &td,
1070 			hostent_test_getaddrinfo_eq, NULL);
1071 		break;
1072 	case TEST_GETHOSTBYADDR_GETNAMEINFO:
1073 		rv = DO_1PASS_TEST(hostent, &td,
1074 			hostent_test_getnameinfo_eq, NULL);
1075 		break;
1076 	case TEST_BUILD_SNAPSHOT:
1077 		if (snapshot_file != NULL) {
1078 		    rv = TEST_SNAPSHOT_FILE_WRITE(hostent, snapshot_file, &td,
1079 			sdump_hostent);
1080 		}
1081 		break;
1082 	case TEST_BUILD_ADDR_SNAPSHOT:
1083 		if (snapshot_file != NULL) {
1084 			rv = DO_1PASS_TEST(hostent, &td,
1085 				hostent_test_gethostbyaddr, (void *)&td_addr);
1086 
1087 		    rv = TEST_SNAPSHOT_FILE_WRITE(hostent, snapshot_file,
1088 			&td_addr, sdump_hostent);
1089 		}
1090 		break;
1091 	default:
1092 		rv = 0;
1093 		break;
1094 	};
1095 
1096 fin:
1097 	TEST_DATA_DESTROY(hostent, &td_snap);
1098 	TEST_DATA_DESTROY(hostent, &td_addr);
1099 	TEST_DATA_DESTROY(hostent, &td);
1100 	free(hostlist_file);
1101 	free(snapshot_file);
1102 
1103 	return (rv);
1104 }
1105 
1106