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