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