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/types.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, void *mdata) 129 { 130 int rv; 131 132 printf("testing equality of 2 addrinfo structures\n"); 133 134 rv = compare_addrinfo_(ai1, ai2); 135 136 if (rv == 0) 137 printf("equal\n"); 138 else { 139 dump_addrinfo(ai1); 140 dump_addrinfo(ai2); 141 printf("not equal\n"); 142 } 143 144 return (rv); 145 } 146 147 void 148 free_addrinfo(struct addrinfo *ai) 149 { 150 if (ai == NULL) 151 return; 152 153 free(ai->ai_addr); 154 free(ai->ai_canonname); 155 free_addrinfo(ai->ai_next); 156 } 157 158 void 159 sdump_addrinfo(struct addrinfo *ai, char *buffer, size_t buflen) 160 { 161 int written, i; 162 163 written = snprintf(buffer, buflen, "%d %d %d %d %d ", 164 ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol, 165 ai->ai_addrlen); 166 buffer += written; 167 if (written > buflen) 168 return; 169 buflen -= written; 170 171 written = snprintf(buffer, buflen, "%s ", 172 ai->ai_canonname == NULL ? "(null)" : ai->ai_canonname); 173 buffer += written; 174 if (written > buflen) 175 return; 176 buflen -= written; 177 178 if (ai->ai_addr == NULL) { 179 written = snprintf(buffer, buflen, "(null)"); 180 buffer += written; 181 if (written > buflen) 182 return; 183 buflen -= written; 184 } else { 185 for (i = 0; i < ai->ai_addrlen; i++) { 186 written = snprintf(buffer, buflen, 187 i + 1 != ai->ai_addrlen ? "%d." : "%d", 188 ((unsigned char *)ai->ai_addr)[i]); 189 buffer += written; 190 if (written > buflen) 191 return; 192 buflen -= written; 193 194 if (buflen == 0) 195 return; 196 } 197 } 198 199 if (ai->ai_next != NULL) { 200 written = snprintf(buffer, buflen, ":"); 201 buffer += written; 202 if (written > buflen) 203 return; 204 buflen -= written; 205 206 sdump_addrinfo(ai->ai_next, buffer, buflen); 207 } 208 } 209 210 void 211 dump_addrinfo(struct addrinfo *result) 212 { 213 if (result != NULL) { 214 char buffer[2048]; 215 sdump_addrinfo(result, buffer, sizeof(buffer)); 216 printf("%s\n", buffer); 217 } else 218 printf("(null)\n"); 219 } 220 221 static int 222 addrinfo_read_snapshot_addr(char *addr, unsigned char *result, size_t len) 223 { 224 char *s, *ps, *ts; 225 226 ps = addr; 227 while ((s = strsep(&ps, ".")) != NULL) { 228 if (len == 0) 229 return (-1); 230 231 *result = (unsigned char)strtol(s, &ts, 10); 232 ++result; 233 if (*ts != '\0') 234 return (-1); 235 236 --len; 237 } 238 if (len != 0) 239 return (-1); 240 else 241 return (0); 242 } 243 244 static int 245 addrinfo_read_snapshot_ai(struct addrinfo *ai, char *line) 246 { 247 char *s, *ps, *ts; 248 int i, rv, *pi; 249 250 rv = 0; 251 i = 0; 252 ps = line; 253 memset(ai, 0, sizeof(struct addrinfo)); 254 while ((s = strsep(&ps, " ")) != NULL) { 255 switch (i) { 256 case 0: 257 case 1: 258 case 2: 259 case 3: 260 pi = &ai->ai_flags + i; 261 *pi = (int)strtol(s, &ts, 10); 262 if (*ts != '\0') 263 goto fin; 264 break; 265 case 4: 266 ai->ai_addrlen = (socklen_t)strtol(s, &ts, 10); 267 if (*ts != '\0') 268 goto fin; 269 break; 270 case 5: 271 if (strcmp(s, "(null)") != 0) { 272 ai->ai_canonname = strdup(s); 273 ATF_REQUIRE(ai->ai_canonname != NULL); 274 } 275 break; 276 case 6: 277 if (strcmp(s, "(null)") != 0) { 278 ai->ai_addr = calloc(1, ai->ai_addrlen); 279 ATF_REQUIRE(ai->ai_addr != NULL); 280 rv = addrinfo_read_snapshot_addr(s, 281 (unsigned char *)ai->ai_addr, 282 ai->ai_addrlen); 283 284 if (rv != 0) 285 goto fin; 286 } 287 break; 288 default: 289 /* NOTE: should not be reachable */ 290 rv = -1; 291 goto fin; 292 } 293 294 ++i; 295 } 296 297 fin: 298 if (i != 7 || rv != 0) { 299 free_addrinfo(ai); 300 ai = NULL; 301 return (-1); 302 } 303 304 return (0); 305 } 306 307 static int 308 addrinfo_read_snapshot_func(struct addrinfo *ai, char *line) 309 { 310 struct addrinfo *ai2; 311 char *s, *ps; 312 int i, rv; 313 314 printf("1 line read from snapshot:\n%s\n", line); 315 316 rv = 0; 317 i = 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) 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 void 413 run_tests(char *hostlist_file, char *snapshot_file, int ai_family) 414 { 415 struct addrinfo_test_data td, td_snap; 416 int rv; 417 418 memset(&hints, 0, sizeof(struct addrinfo)); 419 hints.ai_family = ai_family; 420 hints.ai_flags = AI_CANONNAME; 421 422 if (snapshot_file != NULL) 423 method = TEST_BUILD_SNAPSHOT; 424 425 TEST_DATA_INIT(addrinfo, &td, clone_addrinfo, free_addrinfo); 426 TEST_DATA_INIT(addrinfo, &td_snap, clone_addrinfo, free_addrinfo); 427 428 ATF_REQUIRE_MSG(access(hostlist_file, R_OK) == 0, 429 "can't access the hostlist file %s\n", hostlist_file); 430 431 printf("building host lists from %s\n", hostlist_file); 432 433 rv = TEST_SNAPSHOT_FILE_READ(addrinfo, hostlist_file, &td, 434 addrinfo_read_hostlist_func); 435 if (rv != 0) 436 goto fin; 437 438 if (snapshot_file != NULL) { 439 if (access(snapshot_file, W_OK | R_OK) != 0) { 440 if (errno == ENOENT) 441 method = TEST_BUILD_SNAPSHOT; 442 else { 443 printf("can't access the snapshot " 444 "file %s\n", snapshot_file); 445 446 rv = -1; 447 goto fin; 448 } 449 } else { 450 rv = TEST_SNAPSHOT_FILE_READ(addrinfo, snapshot_file, 451 &td_snap, addrinfo_read_snapshot_func); 452 if (rv != 0) { 453 printf("error reading snapshot file: %s\n", 454 strerror(errno)); 455 goto fin; 456 } 457 } 458 } 459 460 switch (method) { 461 case TEST_GETADDRINFO: 462 if (snapshot_file != NULL) 463 ATF_CHECK(DO_2PASS_TEST(addrinfo, &td, &td_snap, 464 compare_addrinfo, NULL) == 0); 465 break; 466 case TEST_BUILD_SNAPSHOT: 467 if (snapshot_file != NULL) { 468 ATF_CHECK(TEST_SNAPSHOT_FILE_WRITE(addrinfo, 469 snapshot_file, &td, sdump_addrinfo) == 0); 470 } 471 break; 472 default: 473 break; 474 } 475 476 fin: 477 TEST_DATA_DESTROY(addrinfo, &td_snap); 478 TEST_DATA_DESTROY(addrinfo, &td); 479 480 free(hostlist_file); 481 free(snapshot_file); 482 } 483 484 #define HOSTLIST_FILE "mach" 485 #define RUN_TESTS(tc, snapshot_file, ai_family) do { \ 486 char *_hostlist_file; \ 487 char *_snapshot_file; \ 488 ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \ 489 atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \ 490 if (snapshot_file == NULL) \ 491 _snapshot_file = NULL; \ 492 else { \ 493 _snapshot_file = strdup(snapshot_file); \ 494 ATF_REQUIRE(_snapshot_file != NULL); \ 495 } \ 496 run_tests(_hostlist_file, _snapshot_file, ai_family); \ 497 } while(0) 498 499 ATF_TC_WITHOUT_HEAD(pf_unspec); 500 ATF_TC_BODY(pf_unspec, tc) 501 { 502 503 RUN_TESTS(tc, NULL, AF_UNSPEC); 504 } 505 506 ATF_TC_WITHOUT_HEAD(pf_unspec_with_snapshot); 507 ATF_TC_BODY(pf_unspec_with_snapshot, tc) 508 { 509 510 RUN_TESTS(tc, "snapshot_ai", AF_UNSPEC); 511 } 512 513 ATF_TC_WITHOUT_HEAD(pf_inet); 514 ATF_TC_BODY(pf_inet, tc) 515 { 516 517 ATF_REQUIRE_FEATURE("inet"); 518 RUN_TESTS(tc, NULL, AF_INET); 519 } 520 521 ATF_TC_WITHOUT_HEAD(pf_inet_with_snapshot); 522 ATF_TC_BODY(pf_inet_with_snapshot, tc) 523 { 524 525 ATF_REQUIRE_FEATURE("inet"); 526 RUN_TESTS(tc, "snapshot_ai4", AF_INET); 527 } 528 529 ATF_TC_WITHOUT_HEAD(pf_inet6); 530 ATF_TC_BODY(pf_inet6, tc) 531 { 532 533 ATF_REQUIRE_FEATURE("inet6"); 534 RUN_TESTS(tc, NULL, AF_INET6); 535 } 536 537 ATF_TC_WITHOUT_HEAD(pf_inet6_with_snapshot); 538 ATF_TC_BODY(pf_inet6_with_snapshot, tc) 539 { 540 541 ATF_REQUIRE_FEATURE("inet6"); 542 RUN_TESTS(tc, "snapshot_ai6", AF_INET6); 543 } 544 545 ATF_TP_ADD_TCS(tp) 546 { 547 548 ATF_TP_ADD_TC(tp, pf_unspec); 549 ATF_TP_ADD_TC(tp, pf_unspec_with_snapshot); 550 ATF_TP_ADD_TC(tp, pf_inet); 551 ATF_TP_ADD_TC(tp, pf_inet_with_snapshot); 552 ATF_TP_ADD_TC(tp, pf_inet6); 553 ATF_TP_ADD_TC(tp, pf_inet6_with_snapshot); 554 555 return (atf_no_error()); 556 } 557