getaddrinfo_test.c revision 321143
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/11/lib/libc/tests/nss/getaddrinfo_test.c 321143 2017-07-18 18:09:16Z ngie $");
30
31#include <sys/param.h>
32#include <sys/socket.h>
33#include <arpa/inet.h>
34#include <netinet/in.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
44#include <atf-c.h>
45
46#include "freebsd_test_suite/macros.h"
47#include "testutil.h"
48
49enum test_methods {
50	TEST_GETADDRINFO,
51	TEST_BUILD_SNAPSHOT
52};
53
54static struct addrinfo hints;
55static enum test_methods method = TEST_GETADDRINFO;
56
57DECLARE_TEST_DATA(addrinfo)
58DECLARE_TEST_FILE_SNAPSHOT(addrinfo)
59DECLARE_2PASS_TEST(addrinfo)
60
61static void clone_addrinfo(struct addrinfo *, struct addrinfo const *);
62static int compare_addrinfo(struct addrinfo *, struct addrinfo *, void *);
63static void dump_addrinfo(struct addrinfo *);
64
65static void sdump_addrinfo(struct addrinfo *, char *, size_t);
66
67IMPLEMENT_TEST_DATA(addrinfo)
68IMPLEMENT_TEST_FILE_SNAPSHOT(addrinfo)
69IMPLEMENT_2PASS_TEST(addrinfo)
70
71static void
72clone_addrinfo(struct addrinfo *dest, struct addrinfo const *src)
73{
74
75	ATF_REQUIRE(dest != NULL);
76	ATF_REQUIRE(src != NULL);
77
78	memcpy(dest, src, sizeof(struct addrinfo));
79	if (src->ai_canonname != NULL)
80		dest->ai_canonname = strdup(src->ai_canonname);
81
82	if (src->ai_addr != NULL) {
83		dest->ai_addr = malloc(src->ai_addrlen);
84		ATF_REQUIRE(dest->ai_addr != NULL);
85		memcpy(dest->ai_addr, src->ai_addr, src->ai_addrlen);
86	}
87
88	if (src->ai_next != NULL) {
89		dest->ai_next = malloc(sizeof(struct addrinfo));
90		ATF_REQUIRE(dest->ai_next != NULL);
91		clone_addrinfo(dest->ai_next, src->ai_next);
92	}
93}
94
95static int
96compare_addrinfo_(struct addrinfo *ai1, struct addrinfo *ai2)
97{
98
99	if ((ai1 == NULL) || (ai2 == NULL))
100		return (-1);
101
102	if (ai1->ai_flags != ai2->ai_flags ||
103	    ai1->ai_family != ai2->ai_family ||
104	    ai1->ai_socktype != ai2->ai_socktype ||
105	    ai1->ai_protocol != ai2->ai_protocol ||
106	    ai1->ai_addrlen != ai2->ai_addrlen ||
107	    ((ai1->ai_addr == NULL || ai2->ai_addr == NULL) &&
108	     ai1->ai_addr != ai2->ai_addr) ||
109	    ((ai1->ai_canonname == NULL || ai2->ai_canonname == NULL) &&
110	     ai1->ai_canonname != ai2->ai_canonname))
111		return (-1);
112
113	if (ai1->ai_canonname != NULL &&
114	    strcmp(ai1->ai_canonname, ai2->ai_canonname) != 0)
115		return (-1);
116
117	if (ai1->ai_addr != NULL &&
118	    memcmp(ai1->ai_addr, ai2->ai_addr, ai1->ai_addrlen) != 0)
119		return (-1);
120
121	if (ai1->ai_next == NULL && ai2->ai_next == NULL)
122		return (0);
123	else
124		return (compare_addrinfo_(ai1->ai_next, ai2->ai_next));
125}
126
127static int
128compare_addrinfo(struct addrinfo *ai1, struct addrinfo *ai2,
129    void *mdata __unused)
130{
131	int rv;
132
133	printf("testing equality of 2 addrinfo structures\n");
134
135	rv = compare_addrinfo_(ai1, ai2);
136
137	if (rv == 0)
138		printf("equal\n");
139	else {
140		dump_addrinfo(ai1);
141		dump_addrinfo(ai2);
142		printf("not equal\n");
143	}
144
145	return (rv);
146}
147
148static void
149free_addrinfo(struct addrinfo *ai)
150{
151	if (ai == NULL)
152		return;
153
154	free(ai->ai_addr);
155	free(ai->ai_canonname);
156	free_addrinfo(ai->ai_next);
157}
158
159void
160sdump_addrinfo(struct addrinfo *ai, char *buffer, size_t buflen)
161{
162	int written, i;
163
164	written = snprintf(buffer, buflen, "%d %d %d %d %d ",
165		ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol,
166		ai->ai_addrlen);
167	buffer += written;
168	if (written > (int)buflen)
169		return;
170	buflen -= written;
171
172	written = snprintf(buffer, buflen, "%s ",
173		ai->ai_canonname == NULL ? "(null)" : ai->ai_canonname);
174	buffer += written;
175	if (written > (int)buflen)
176		return;
177	buflen -= written;
178
179	if (ai->ai_addr == NULL) {
180		written = snprintf(buffer, buflen, "(null)");
181		buffer += written;
182		if (written > (int)buflen)
183			return;
184		buflen -= written;
185	} else {
186		for (i = 0; i < (int)ai->ai_addrlen; i++) {
187			written = snprintf(buffer, buflen,
188			    i + 1 != (int)ai->ai_addrlen ? "%d." : "%d",
189			    ((unsigned char *)ai->ai_addr)[i]);
190			buffer += written;
191			if (written > (int)buflen)
192				return;
193			buflen -= written;
194
195			if (buflen == 0)
196				return;
197		}
198	}
199
200	if (ai->ai_next != NULL) {
201		written = snprintf(buffer, buflen, ":");
202		buffer += written;
203		if (written > (int)buflen)
204			return;
205		buflen -= written;
206
207		sdump_addrinfo(ai->ai_next, buffer, buflen);
208	}
209}
210
211void
212dump_addrinfo(struct addrinfo *result)
213{
214	if (result != NULL) {
215		char buffer[2048];
216		sdump_addrinfo(result, buffer, sizeof(buffer));
217		printf("%s\n", buffer);
218	} else
219		printf("(null)\n");
220}
221
222static int
223addrinfo_read_snapshot_addr(char *addr, unsigned char *result, size_t len)
224{
225	char *s, *ps, *ts;
226
227	ps = addr;
228	while ((s = strsep(&ps, ".")) != NULL) {
229		if (len == 0)
230			return (-1);
231
232		*result = (unsigned char)strtol(s, &ts, 10);
233		++result;
234		if (*ts != '\0')
235			return (-1);
236
237		--len;
238	}
239	if (len != 0)
240		return (-1);
241	else
242		return (0);
243}
244
245static int
246addrinfo_read_snapshot_ai(struct addrinfo *ai, char *line)
247{
248	char *s, *ps, *ts;
249	int i, rv, *pi;
250
251	rv = 0;
252	i = 0;
253	ps = line;
254	memset(ai, 0, sizeof(struct addrinfo));
255	while ((s = strsep(&ps, " ")) != NULL) {
256		switch (i) {
257		case 0:
258		case 1:
259		case 2:
260		case 3:
261			pi = &ai->ai_flags + i;
262			*pi = (int)strtol(s, &ts, 10);
263			if (*ts != '\0')
264				goto fin;
265			break;
266		case 4:
267			ai->ai_addrlen = (socklen_t)strtol(s, &ts, 10);
268			if (*ts != '\0')
269				goto fin;
270			break;
271		case 5:
272			if (strcmp(s, "(null)") != 0) {
273				ai->ai_canonname = strdup(s);
274				ATF_REQUIRE(ai->ai_canonname != NULL);
275			}
276			break;
277		case 6:
278			if (strcmp(s, "(null)") != 0) {
279				ai->ai_addr = calloc(1, ai->ai_addrlen);
280				ATF_REQUIRE(ai->ai_addr != NULL);
281				rv = addrinfo_read_snapshot_addr(s,
282				    (unsigned char *)ai->ai_addr,
283				    ai->ai_addrlen);
284
285				if (rv != 0)
286					goto fin;
287			}
288			break;
289		default:
290			/* NOTE: should not be reachable */
291			rv = -1;
292			goto fin;
293		}
294
295		++i;
296	}
297
298fin:
299	if (i != 7 || rv != 0) {
300		free_addrinfo(ai);
301		ai = NULL;
302		return (-1);
303	}
304
305	return (0);
306}
307
308static int
309addrinfo_read_snapshot_func(struct addrinfo *ai, char *line)
310{
311	struct addrinfo *ai2;
312	char *s, *ps;
313	int rv;
314
315	printf("1 line read from snapshot:\n%s\n", line);
316
317	rv = 0;
318	ps = line;
319
320	s = strsep(&ps, ":");
321	if (s == NULL)
322		return (-1);
323
324	rv = addrinfo_read_snapshot_ai(ai, s);
325	if (rv != 0)
326		return (-1);
327
328	ai2 = ai;
329	while ((s = strsep(&ps, ":")) != NULL) {
330		ai2->ai_next = calloc(1, sizeof(struct addrinfo));
331		ATF_REQUIRE(ai2->ai_next != NULL);
332
333		rv = addrinfo_read_snapshot_ai(ai2->ai_next, s);
334		if (rv != 0) {
335			free_addrinfo(ai);
336			ai = NULL;
337			return (-1);
338		}
339
340		ai2 = ai2->ai_next;
341	}
342
343	return (0);
344}
345
346static int
347addrinfo_test_correctness(struct addrinfo *ai, void *mdata __unused)
348{
349
350	printf("testing correctness with the following data:\n");
351	dump_addrinfo(ai);
352
353	if (ai == NULL)
354		goto errfin;
355
356	if (!(ai->ai_family >= 0 && ai->ai_family < AF_MAX))
357		goto errfin;
358
359	if (ai->ai_socktype != 0 && ai->ai_socktype != SOCK_STREAM &&
360	    ai->ai_socktype != SOCK_DGRAM && ai->ai_socktype != SOCK_RAW)
361		goto errfin;
362
363	if (ai->ai_protocol != 0 && ai->ai_protocol != IPPROTO_UDP &&
364	    ai->ai_protocol != IPPROTO_TCP)
365		goto errfin;
366
367	if ((ai->ai_flags & ~(AI_CANONNAME | AI_NUMERICHOST | AI_PASSIVE)) != 0)
368		goto errfin;
369
370	if (ai->ai_addrlen != ai->ai_addr->sa_len ||
371	    ai->ai_family != ai->ai_addr->sa_family)
372		goto errfin;
373
374	printf("correct\n");
375
376	return (0);
377errfin:
378	printf("incorrect\n");
379
380	return (-1);
381}
382
383static int
384addrinfo_read_hostlist_func(struct addrinfo *ai, char *line)
385{
386	struct addrinfo *result;
387	int rv;
388
389	printf("resolving %s: ", line);
390	rv = getaddrinfo(line, NULL, &hints, &result);
391	if (rv == 0) {
392		printf("found\n");
393
394		rv = addrinfo_test_correctness(result, NULL);
395		if (rv != 0) {
396			freeaddrinfo(result);
397			result = NULL;
398			return (rv);
399		}
400
401		clone_addrinfo(ai, result);
402		freeaddrinfo(result);
403		result = NULL;
404	} else {
405		printf("not found\n");
406
407 		memset(ai, 0, sizeof(struct addrinfo));
408	}
409	return (0);
410}
411
412static void
413run_tests(char *hostlist_file, const char *snapshot_file, int ai_family)
414{
415	struct addrinfo_test_data td, td_snap;
416	char *snapshot_file_copy;
417	int rv;
418
419	if (snapshot_file == NULL)
420		snapshot_file_copy = NULL;
421	else {
422		snapshot_file_copy = strdup(snapshot_file);
423		ATF_REQUIRE(snapshot_file_copy != NULL);
424	}
425
426	memset(&hints, 0, sizeof(struct addrinfo));
427	hints.ai_family = ai_family;
428	hints.ai_flags = AI_CANONNAME;
429
430	if (snapshot_file != NULL)
431		method = TEST_BUILD_SNAPSHOT;
432
433	TEST_DATA_INIT(addrinfo, &td, clone_addrinfo, free_addrinfo);
434	TEST_DATA_INIT(addrinfo, &td_snap, clone_addrinfo, free_addrinfo);
435
436	ATF_REQUIRE_MSG(access(hostlist_file, R_OK) == 0,
437		"can't access the hostlist file %s\n", hostlist_file);
438
439	printf("building host lists from %s\n", hostlist_file);
440
441	rv = TEST_SNAPSHOT_FILE_READ(addrinfo, hostlist_file, &td,
442		addrinfo_read_hostlist_func);
443	if (rv != 0)
444		goto fin;
445
446	if (snapshot_file != NULL) {
447		if (access(snapshot_file, W_OK | R_OK) != 0) {
448			if (errno == ENOENT)
449				method = TEST_BUILD_SNAPSHOT;
450			else {
451				printf("can't access the snapshot "
452				    "file %s\n", snapshot_file);
453
454				rv = -1;
455				goto fin;
456			}
457		} else {
458			rv = TEST_SNAPSHOT_FILE_READ(addrinfo, snapshot_file,
459				&td_snap, addrinfo_read_snapshot_func);
460			if (rv != 0) {
461				printf("error reading snapshot file: %s\n",
462				    strerror(errno));
463				goto fin;
464			}
465		}
466	}
467
468	switch (method) {
469	case TEST_GETADDRINFO:
470		if (snapshot_file != NULL)
471			ATF_CHECK(DO_2PASS_TEST(addrinfo, &td, &td_snap,
472				compare_addrinfo, NULL) == 0);
473		break;
474	case TEST_BUILD_SNAPSHOT:
475		if (snapshot_file != NULL) {
476			ATF_CHECK(TEST_SNAPSHOT_FILE_WRITE(addrinfo,
477			    snapshot_file, &td, sdump_addrinfo) == 0);
478		}
479		break;
480	default:
481		break;
482	}
483
484fin:
485	TEST_DATA_DESTROY(addrinfo, &td_snap);
486	TEST_DATA_DESTROY(addrinfo, &td);
487
488	free(snapshot_file_copy);
489}
490
491#define	HOSTLIST_FILE	"mach"
492#define	RUN_TESTS(tc, snapshot_file, ai_family) do {			\
493	char *_hostlist_file;						\
494	ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s",		\
495	    atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE));	\
496	run_tests(_hostlist_file, snapshot_file, ai_family);		\
497	free(_hostlist_file);						\
498} while (0)
499
500ATF_TC_WITHOUT_HEAD(pf_unspec);
501ATF_TC_BODY(pf_unspec, tc)
502{
503
504	RUN_TESTS(tc, NULL, AF_UNSPEC);
505}
506
507ATF_TC_WITHOUT_HEAD(pf_unspec_with_snapshot);
508ATF_TC_BODY(pf_unspec_with_snapshot, tc)
509{
510
511	RUN_TESTS(tc, "snapshot_ai", AF_UNSPEC);
512}
513
514ATF_TC_WITHOUT_HEAD(pf_inet);
515ATF_TC_BODY(pf_inet, tc)
516{
517
518	ATF_REQUIRE_FEATURE("inet");
519	RUN_TESTS(tc, NULL, AF_INET);
520}
521
522ATF_TC_WITHOUT_HEAD(pf_inet_with_snapshot);
523ATF_TC_BODY(pf_inet_with_snapshot, tc)
524{
525
526	ATF_REQUIRE_FEATURE("inet");
527	RUN_TESTS(tc, "snapshot_ai4", AF_INET);
528}
529
530ATF_TC_WITHOUT_HEAD(pf_inet6);
531ATF_TC_BODY(pf_inet6, tc)
532{
533
534	ATF_REQUIRE_FEATURE("inet6");
535	RUN_TESTS(tc, NULL, AF_INET6);
536}
537
538ATF_TC_WITHOUT_HEAD(pf_inet6_with_snapshot);
539ATF_TC_BODY(pf_inet6_with_snapshot, tc)
540{
541
542	ATF_REQUIRE_FEATURE("inet6");
543	RUN_TESTS(tc, "snapshot_ai6", AF_INET6);
544}
545
546ATF_TP_ADD_TCS(tp)
547{
548
549	ATF_TP_ADD_TC(tp, pf_unspec);
550	ATF_TP_ADD_TC(tp, pf_unspec_with_snapshot);
551	ATF_TP_ADD_TC(tp, pf_inet);
552	ATF_TP_ADD_TC(tp, pf_inet_with_snapshot);
553	ATF_TP_ADD_TC(tp, pf_inet6);
554	ATF_TP_ADD_TC(tp, pf_inet6_with_snapshot);
555
556	return (atf_no_error());
557}
558