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)
IMPLEMENT_TEST_FILE_SNAPSHOT(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
compare_addrinfo_(struct addrinfo * ai1,struct addrinfo * ai2)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
compare_addrinfo(struct addrinfo * ai1,struct addrinfo * ai2,void * mdata __unused)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
free_addrinfo(struct addrinfo * ai)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
sdump_addrinfo(struct addrinfo * ai,char * buffer,size_t buflen)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
dump_addrinfo(struct addrinfo * result)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
addrinfo_read_snapshot_addr(char * addr,unsigned char * result,size_t len)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
addrinfo_read_snapshot_ai(struct addrinfo * ai,char * line)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
addrinfo_read_snapshot_func(struct addrinfo * ai,char * line)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
addrinfo_test_correctness(struct addrinfo * ai,void * mdata __unused)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
addrinfo_read_hostlist_func(struct addrinfo * ai,char * line)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
run_tests(char * hostlist_file,const char * snapshot_file,int ai_family)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);
ATF_TC_BODY(pf_unspec,tc)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);
ATF_TC_BODY(pf_unspec_with_snapshot,tc)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);
ATF_TC_BODY(pf_inet,tc)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);
ATF_TC_BODY(pf_inet_with_snapshot,tc)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);
ATF_TC_BODY(pf_inet6,tc)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);
ATF_TC_BODY(pf_inet6_with_snapshot,tc)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
ATF_TP_ADD_TCS(tp)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