getaddrinfo_test.c revision 251818
1/*- 2 * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 * 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/tools/regression/lib/libc/nss/test-getaddr.c 251818 2013-06-16 19:35:01Z eadler $"); 29 30#include <arpa/inet.h> 31#include <sys/socket.h> 32#include <sys/types.h> 33#include <netinet/in.h> 34#include <assert.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#include "testutil.h" 44 45enum test_methods { 46 TEST_GETADDRINFO, 47 TEST_BUILD_SNAPSHOT 48}; 49 50static int debug = 0; 51static struct addrinfo hints; 52static enum test_methods method = TEST_GETADDRINFO; 53 54DECLARE_TEST_DATA(addrinfo) 55DECLARE_TEST_FILE_SNAPSHOT(addrinfo) 56DECLARE_2PASS_TEST(addrinfo) 57 58static void clone_addrinfo(struct addrinfo *, struct addrinfo const *); 59static int compare_addrinfo(struct addrinfo *, struct addrinfo *, void *); 60static void dump_addrinfo(struct addrinfo *); 61static void free_addrinfo(struct addrinfo *); 62 63static void sdump_addrinfo(struct addrinfo *, char *, size_t); 64 65IMPLEMENT_TEST_DATA(addrinfo) 66IMPLEMENT_TEST_FILE_SNAPSHOT(addrinfo) 67IMPLEMENT_2PASS_TEST(addrinfo) 68 69static void 70clone_addrinfo(struct addrinfo *dest, struct addrinfo const *src) 71{ 72 assert(dest != NULL); 73 assert(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 = (struct sockaddr *)malloc(src->ai_addrlen); 81 assert(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 = (struct addrinfo *)malloc( 87 sizeof(struct addrinfo)); 88 assert(dest->ai_next != NULL); 89 clone_addrinfo(dest->ai_next, src->ai_next); 90 } 91} 92 93static int 94compare_addrinfo_(struct addrinfo *ai1, struct addrinfo *ai2) 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 124static int 125compare_addrinfo(struct addrinfo *ai1, struct addrinfo *ai2, void *mdata) 126{ 127 int rv; 128 129 if (debug) { 130 printf("testing equality of 2 addrinfo structures\n"); 131 } 132 133 rv = compare_addrinfo_(ai1, ai2); 134 135 if (debug) { 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 145 return (rv); 146} 147 148void 149free_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 159void 160sdump_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 > 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 > 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 > buflen) 183 return; 184 buflen -= written; 185 } else { 186 for (i = 0; i < ai->ai_addrlen; ++i ) { 187 written = snprintf(buffer, buflen, 188 i + 1 != ai->ai_addrlen ? "%d." : "%d", 189 ((unsigned char *)ai->ai_addr)[i]); 190 buffer += written; 191 if (written > 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 > buflen) 204 return; 205 buflen -= written; 206 207 sdump_addrinfo(ai->ai_next, buffer, buflen); 208 } 209} 210 211void 212dump_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 222static int 223addrinfo_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 245static int 246addrinfo_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 assert(ai->ai_canonname != NULL); 275 } 276 break; 277 case 6: 278 if (strcmp(s, "(null)") != 0) { 279 ai->ai_addr = (struct sockaddr *)malloc( 280 ai->ai_addrlen); 281 assert(ai->ai_addr != NULL); 282 memset(ai->ai_addr, 0, ai->ai_addrlen); 283 rv = addrinfo_read_snapshot_addr(s, 284 (unsigned char *)ai->ai_addr, 285 ai->ai_addrlen); 286 287 if (rv != 0) 288 goto fin; 289 } 290 break; 291 default: 292 /* NOTE: should not be reachable */ 293 rv = -1; 294 goto fin; 295 }; 296 297 ++i; 298 } 299 300fin: 301 if ((i != 7) || (rv != 0)) { 302 free_addrinfo(ai); 303 memset(ai, 0, sizeof(struct addrinfo)); 304 return (-1); 305 } 306 307 return (0); 308} 309 310static int 311addrinfo_read_snapshot_func(struct addrinfo *ai, char *line) 312{ 313 struct addrinfo *ai2; 314 char *s, *ps; 315 int i, rv; 316 317 if (debug) 318 printf("1 line read from snapshot:\n%s\n", line); 319 320 rv = 0; 321 i = 0; 322 ps = line; 323 324 s = strsep(&ps, ":"); 325 if (s == NULL) 326 return (-1); 327 328 rv = addrinfo_read_snapshot_ai(ai, s); 329 if (rv != 0) 330 return (-1); 331 332 ai2 = ai; 333 while ( (s = strsep(&ps, ":")) != NULL) { 334 ai2->ai_next = (struct addrinfo *)malloc( 335 sizeof(struct addrinfo)); 336 assert(ai2->ai_next != NULL); 337 memset(ai2->ai_next, 0, sizeof(struct addrinfo)); 338 339 rv = addrinfo_read_snapshot_ai(ai2->ai_next, s); 340 if (rv != 0) { 341 free_addrinfo(ai); 342 return (-1); 343 } 344 345 ai2 = ai2->ai_next; 346 } 347 348 return (0); 349} 350 351static int 352addrinfo_test_correctness(struct addrinfo *ai, void *mdata) 353{ 354 if (debug) { 355 printf("testing correctness with the following data:\n"); 356 dump_addrinfo(ai); 357 } 358 359 if (ai == NULL) 360 goto errfin; 361 362 if (!((ai->ai_family >= 0) && (ai->ai_family < AF_MAX))) 363 goto errfin; 364 365 if ((ai->ai_socktype != 0) && (ai->ai_socktype != SOCK_STREAM) && 366 (ai->ai_socktype != SOCK_DGRAM) && (ai->ai_socktype != SOCK_RAW)) 367 goto errfin; 368 369 if ((ai->ai_protocol != 0) && (ai->ai_protocol != IPPROTO_UDP) && 370 (ai->ai_protocol != IPPROTO_TCP)) 371 goto errfin; 372 373 if ((ai->ai_flags & ~(AI_CANONNAME | AI_NUMERICHOST | AI_PASSIVE)) != 0) 374 goto errfin; 375 376 if ((ai->ai_addrlen != ai->ai_addr->sa_len) || 377 (ai->ai_family != ai->ai_addr->sa_family)) 378 goto errfin; 379 380 if (debug) 381 printf("correct\n"); 382 383 return (0); 384errfin: 385 if (debug) 386 printf("incorrect\n"); 387 388 return (-1); 389} 390 391static int 392addrinfo_read_hostlist_func(struct addrinfo *ai, char *line) 393{ 394 struct addrinfo *result; 395 int rv; 396 397 if (debug) 398 printf("resolving %s: ", line); 399 rv = getaddrinfo(line, NULL, &hints, &result); 400 if (rv == 0) { 401 if (debug) 402 printf("found\n"); 403 404 rv = addrinfo_test_correctness(result, NULL); 405 if (rv != 0) { 406 freeaddrinfo(result); 407 return (rv); 408 } 409 410 clone_addrinfo(ai, result); 411 freeaddrinfo(result); 412 } else { 413 if (debug) 414 printf("not found\n"); 415 416 memset(ai, 0, sizeof(struct addrinfo)); 417 } 418 return (0); 419} 420 421static void 422usage(void) 423{ 424 (void)fprintf(stderr, 425 "Usage: %s [-d] [-46] [-s <file]> -f <file>\n", 426 getprogname()); 427 exit(1); 428} 429 430int 431main(int argc, char **argv) 432{ 433 struct addrinfo_test_data td, td_snap; 434 char *snapshot_file, *hostlist_file; 435 int rv; 436 int c; 437 438 if (argc < 2) 439 usage(); 440 441 snapshot_file = NULL; 442 hostlist_file = NULL; 443 memset(&hints, 0, sizeof(struct addrinfo)); 444 hints.ai_family = PF_UNSPEC; 445 hints.ai_flags = AI_CANONNAME; 446 while ((c = getopt(argc, argv, "46dns:f:")) != -1) 447 switch (c) { 448 case '4': 449 hints.ai_family = PF_INET; 450 case '6': 451 hints.ai_family = PF_INET6; 452 break; 453 case 'd': 454 debug = 1; 455 break; 456 case 's': 457 snapshot_file = strdup(optarg); 458 method = TEST_BUILD_SNAPSHOT; 459 break; 460 case 'f': 461 hostlist_file = strdup(optarg); 462 break; 463 default: 464 usage(); 465 } 466 467 TEST_DATA_INIT(addrinfo, &td, clone_addrinfo, free_addrinfo); 468 TEST_DATA_INIT(addrinfo, &td_snap, clone_addrinfo, free_addrinfo); 469 470 if (hostlist_file == NULL) 471 usage(); 472 473 if (access(hostlist_file, R_OK) != 0) { 474 if (debug) 475 printf("can't access the hostlist file %s\n", 476 hostlist_file); 477 478 usage(); 479 } 480 481 if (debug) 482 printf("building host lists from %s\n", hostlist_file); 483 484 rv = TEST_SNAPSHOT_FILE_READ(addrinfo, hostlist_file, &td, 485 addrinfo_read_hostlist_func); 486 if (rv != 0) 487 goto fin; 488 489 if (snapshot_file != NULL) { 490 if (access(snapshot_file, W_OK | R_OK) != 0) { 491 if (errno == ENOENT) 492 method = TEST_BUILD_SNAPSHOT; 493 else { 494 if (debug) 495 printf("can't access the snapshot file %s\n", 496 snapshot_file); 497 498 rv = -1; 499 goto fin; 500 } 501 } else { 502 rv = TEST_SNAPSHOT_FILE_READ(addrinfo, snapshot_file, 503 &td_snap, addrinfo_read_snapshot_func); 504 if (rv != 0) { 505 if (debug) 506 printf("error reading snapshot file\n"); 507 goto fin; 508 } 509 } 510 } 511 512 switch (method) { 513 case TEST_GETADDRINFO: 514 if (snapshot_file != NULL) 515 rv = DO_2PASS_TEST(addrinfo, &td, &td_snap, 516 compare_addrinfo, NULL); 517 break; 518 case TEST_BUILD_SNAPSHOT: 519 if (snapshot_file != NULL) { 520 rv = TEST_SNAPSHOT_FILE_WRITE(addrinfo, snapshot_file, &td, 521 sdump_addrinfo); 522 } 523 break; 524 default: 525 rv = 0; 526 break; 527 }; 528 529fin: 530 TEST_DATA_DESTROY(addrinfo, &td_snap); 531 TEST_DATA_DESTROY(addrinfo, &td); 532 free(hostlist_file); 533 free(snapshot_file); 534 return (rv); 535 536} 537 538