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