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