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