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$"); 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 49 enum test_methods { 50 TEST_GETADDRINFO, 51 TEST_BUILD_SNAPSHOT 52 }; 53 54 static struct addrinfo hints; 55 static enum test_methods method = TEST_GETADDRINFO; 56 57 DECLARE_TEST_DATA(addrinfo) 58 DECLARE_TEST_FILE_SNAPSHOT(addrinfo) 59 DECLARE_2PASS_TEST(addrinfo) 60 61 static void clone_addrinfo(struct addrinfo *, struct addrinfo const *); 62 static int compare_addrinfo(struct addrinfo *, struct addrinfo *, void *); 63 static void dump_addrinfo(struct addrinfo *); 64 65 static void sdump_addrinfo(struct addrinfo *, char *, size_t); 66 67 IMPLEMENT_TEST_DATA(addrinfo) 68 IMPLEMENT_TEST_FILE_SNAPSHOT(addrinfo) 69 IMPLEMENT_2PASS_TEST(addrinfo) 70 71 static void 72 clone_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 95 static int 96 compare_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 127 static int 128 compare_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 148 static void 149 free_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 159 void 160 sdump_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 211 void 212 dump_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 222 static int 223 addrinfo_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 245 static int 246 addrinfo_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 298 fin: 299 if (i != 7 || rv != 0) { 300 free_addrinfo(ai); 301 ai = NULL; 302 return (-1); 303 } 304 305 return (0); 306 } 307 308 static int 309 addrinfo_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 346 static int 347 addrinfo_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); 377 errfin: 378 printf("incorrect\n"); 379 380 return (-1); 381 } 382 383 static int 384 addrinfo_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 412 static void 413 run_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 484 fin: 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 500 ATF_TC_WITHOUT_HEAD(pf_unspec); 501 ATF_TC_BODY(pf_unspec, tc) 502 { 503 504 RUN_TESTS(tc, NULL, AF_UNSPEC); 505 } 506 507 ATF_TC_WITHOUT_HEAD(pf_unspec_with_snapshot); 508 ATF_TC_BODY(pf_unspec_with_snapshot, tc) 509 { 510 511 RUN_TESTS(tc, "snapshot_ai", AF_UNSPEC); 512 } 513 514 ATF_TC_WITHOUT_HEAD(pf_inet); 515 ATF_TC_BODY(pf_inet, tc) 516 { 517 518 ATF_REQUIRE_FEATURE("inet"); 519 RUN_TESTS(tc, NULL, AF_INET); 520 } 521 522 ATF_TC_WITHOUT_HEAD(pf_inet_with_snapshot); 523 ATF_TC_BODY(pf_inet_with_snapshot, tc) 524 { 525 526 ATF_REQUIRE_FEATURE("inet"); 527 RUN_TESTS(tc, "snapshot_ai4", AF_INET); 528 } 529 530 ATF_TC_WITHOUT_HEAD(pf_inet6); 531 ATF_TC_BODY(pf_inet6, tc) 532 { 533 534 ATF_REQUIRE_FEATURE("inet6"); 535 RUN_TESTS(tc, NULL, AF_INET6); 536 } 537 538 ATF_TC_WITHOUT_HEAD(pf_inet6_with_snapshot); 539 ATF_TC_BODY(pf_inet6_with_snapshot, tc) 540 { 541 542 ATF_REQUIRE_FEATURE("inet6"); 543 RUN_TESTS(tc, "snapshot_ai6", AF_INET6); 544 } 545 546 ATF_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