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