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$");
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
50enum 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
59static int use_ipnode_functions = 0;
60static int use_ipv6_mapping = 0;
61static int ipnode_flags = 0;
62static int debug = 0;
63static int af_type = AF_INET;
64static enum test_methods method = TEST_BUILD_SNAPSHOT;
65
66DECLARE_TEST_DATA(hostent)
67DECLARE_TEST_FILE_SNAPSHOT(hostent)
68DECLARE_1PASS_TEST(hostent)
69DECLARE_2PASS_TEST(hostent)
70
71/* These stubs will use gethostby***() or getipnodeby***() functions,
72 * depending on the use_ipnode_functions global variable value */
73static struct hostent *__gethostbyname2(const char *, int);
74static struct hostent *__gethostbyaddr(const void *, socklen_t, int);
75static void __freehostent(struct hostent *);
76
77static void clone_hostent(struct hostent *, struct hostent const *);
78static int compare_hostent(struct hostent *, struct hostent *, void *);
79static void dump_hostent(struct hostent *);
80static void free_hostent(struct hostent *);
81
82static int is_hostent_equal(struct hostent *, struct addrinfo *);
83
84static void sdump_hostent(struct hostent *, char *, size_t);
85static int hostent_read_hostlist_func(struct hostent *, char *);
86static int hostent_read_snapshot_addr(char *, unsigned char *, size_t);
87static int hostent_read_snapshot_func(struct hostent *, char *);
88
89static int hostent_test_correctness(struct hostent *, void *);
90static int hostent_test_gethostbyaddr(struct hostent *, void *);
91static int hostent_test_getaddrinfo_eq(struct hostent *, void *);
92static int hostent_test_getnameinfo_eq(struct hostent *, void *);
93
94static void usage(void)  __attribute__((__noreturn__));
95
96IMPLEMENT_TEST_DATA(hostent)
97IMPLEMENT_TEST_FILE_SNAPSHOT(hostent)
98IMPLEMENT_1PASS_TEST(hostent)
99IMPLEMENT_2PASS_TEST(hostent)
100
101static 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
119static struct hostent *
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
137static void
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
145static void
146clone_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
205static void
206free_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
227static  int
228compare_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
335errfin:
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
345static int
346check_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
358static int
359check_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
389static int
390is_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
423static void
424sdump_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
510static int
511hostent_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
542static int
543hostent_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
565static int
566hostent_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
660fin:
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
682static void
683dump_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
693static int
694hostent_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);
724errfin:
725	if (debug)
726		printf("incorrect\n");
727
728	return (-1);
729}
730
731static int
732hostent_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
771static int
772hostent_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
814static int
815hostent_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
912static void
913usage(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
921int
922main(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
1096fin:
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