1 #include <arpa/inet.h> 2 #include <assert.h> 3 #include <netdb.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <unistd.h> 8 9 int max_error = 3; 10 #include "common.h" 11 12 #define err() e(__LINE__) 13 14 static void printstr(const char *s) 15 { 16 if (s) 17 printf("\"%s\"", s); 18 else 19 printf("NULL"); 20 } 21 22 static void test_getaddrinfo_err( 23 int n, 24 const char *nodename, 25 const char *servname, 26 int passhints, 27 int flags, 28 int family, 29 int socktype, 30 const char *exp_result, 31 const char *result) 32 { 33 printf("error %d: getaddrinfo(", n); 34 printstr(nodename); 35 printf(", "); 36 printstr(servname); 37 printf(", "); 38 if (passhints) 39 printf("{ 0x%x, %d, %d }", flags, family, socktype); 40 else 41 printf("NULL"); 42 43 printf("); result: "); 44 printstr(result); 45 printf("; expected: "); 46 printstr(exp_result); 47 printf("\n"); 48 err(); 49 } 50 51 /* yes, this is ugly, but not as ugly as repeating it all every time */ 52 #define TEST_GETADDRINFO_ERR_PARAMS \ 53 nodename, servname, passhints, flags, family, socktype 54 55 static void test_getaddrinfo_err_nr( 56 int n, 57 const char *nodename, 58 const char *servname, 59 int passhints, 60 int flags, 61 int family, 62 int socktype, 63 int exp_result, 64 int result) 65 { 66 char exp_result_s[23], result_s[23]; 67 68 /* convert result to string */ 69 snprintf(exp_result_s, sizeof(exp_result_s), "%d/0x%x", 70 exp_result, exp_result); 71 snprintf(result_s, sizeof(result_s), "%d/0x%x", result, result); 72 test_getaddrinfo_err(n, TEST_GETADDRINFO_ERR_PARAMS, 73 exp_result_s, result_s); 74 } 75 76 static void test_getnameinfo_err( 77 int n, 78 unsigned long ipaddr, 79 unsigned short port, 80 socklen_t nodelen, 81 socklen_t servicelen, 82 int flags, 83 const char *exp_result, 84 const char *result) 85 { 86 printf("error %d: getnameinfo(0x%.8x, %d, %d, %d, 0x%x); result: ", 87 n, ntohl(ipaddr), ntohs(port), nodelen, servicelen, flags); 88 printstr(result); 89 printf("; expected: "); 90 printstr(exp_result); 91 printf("\n"); 92 err(); 93 } 94 95 /* yes, this is ugly, but not as ugly as repeating it all every time */ 96 #define TEST_GETNAMEINFO_ERR_PARAMS ipaddr, port, nodelen, servicelen, flags 97 98 static void test_getnameinfo_err_nr( 99 int n, 100 unsigned long ipaddr, 101 unsigned short port, 102 socklen_t nodelen, 103 socklen_t servicelen, 104 int flags, 105 int exp_result, 106 int result) 107 { 108 char exp_result_s[23], result_s[23]; 109 110 /* convert result to string */ 111 snprintf(exp_result_s, sizeof(exp_result_s), "%d/0x%x", 112 exp_result, exp_result); 113 snprintf(result_s, sizeof(result_s), "%d/0x%x", result, result); 114 test_getnameinfo_err(n, TEST_GETNAMEINFO_ERR_PARAMS, 115 exp_result_s, result_s); 116 } 117 118 static void test_getaddrinfo( 119 const char *nodename, 120 int nodename_numerical, 121 const char *servname, 122 int servname_numerical, 123 int passhints, 124 int flags, 125 int family, 126 int socktype, 127 int exp_results, 128 unsigned long exp_ip, 129 int exp_canonname, 130 unsigned short exp_port) 131 { 132 struct addrinfo *ai, *ai_cur; 133 struct addrinfo hints; 134 struct sockaddr_in *sockaddr_in; 135 int ai_count_dgram, ai_count_stream, r; 136 137 /* some parameters are only meaningful with hints */ 138 assert(passhints || !flags); 139 assert(passhints || family == AF_UNSPEC); 140 assert(passhints || !socktype); 141 142 /* a combination of parameters don't make sense to test */ 143 if (nodename == NULL && servname == NULL) return; 144 if (nodename == NULL && (flags & AI_NUMERICHOST)) return; 145 if (servname == NULL && (flags & AI_NUMERICSERV)) return; 146 147 /* initialize hints */ 148 memset(&hints, 0, sizeof(hints)); 149 hints.ai_flags = flags; 150 hints.ai_family = family; 151 hints.ai_socktype = socktype; 152 153 /* perform query and test result */ 154 ai = (struct addrinfo *) 0xDEADBEEF; 155 r = getaddrinfo(nodename, servname, passhints ? &hints : NULL, &ai); 156 if (r < 0 || r >= 32 || !((1 << r) & exp_results)) 157 test_getaddrinfo_err_nr(1, TEST_GETADDRINFO_ERR_PARAMS, exp_results, r); 158 159 if (r) 160 return; 161 162 /* the function succeeded; do the results make sense? */ 163 ai_cur = ai; 164 ai_count_dgram = 0; 165 ai_count_stream = 0; 166 while (ai_cur) 167 { 168 /* 169 * TODO: this test was written for IPv4. For now, skip IPv6 170 * results altogether. Later, we should add additional code 171 * for IPv6. However, since this test now largely exercises 172 * NetBSD code, it is not as important as it once was. 173 */ 174 if (ai_cur->ai_family == AF_INET6) { 175 ai_cur = ai_cur->ai_next; 176 continue; 177 } 178 179 /* test result fields */ 180 if (ai_cur->ai_family != AF_INET) 181 test_getaddrinfo_err_nr(2, TEST_GETADDRINFO_ERR_PARAMS, 182 AF_INET, ai_cur->ai_family); 183 184 if (socktype && ai_cur->ai_socktype != socktype) 185 test_getaddrinfo_err_nr(3, TEST_GETADDRINFO_ERR_PARAMS, 186 socktype, ai_cur->ai_socktype); 187 188 switch (ai_cur->ai_socktype) 189 { 190 case SOCK_DGRAM: ai_count_dgram++; break; 191 case SOCK_STREAM: ai_count_stream++; break; 192 } 193 194 /* do address and port match? */ 195 if (ai_cur->ai_addrlen != sizeof(struct sockaddr_in)) 196 test_getaddrinfo_err_nr(4, TEST_GETADDRINFO_ERR_PARAMS, 197 sizeof(struct sockaddr_in), 198 ai_cur->ai_addrlen); 199 else 200 { 201 sockaddr_in = (struct sockaddr_in *) ai_cur->ai_addr; 202 if (sockaddr_in->sin_addr.s_addr != exp_ip) 203 test_getaddrinfo_err_nr(5, 204 TEST_GETADDRINFO_ERR_PARAMS, 205 ntohl(exp_ip), 206 ntohl(sockaddr_in->sin_addr.s_addr)); 207 208 if (sockaddr_in->sin_port != exp_port) 209 test_getaddrinfo_err_nr(6, 210 TEST_GETADDRINFO_ERR_PARAMS, 211 ntohs(exp_port), 212 ntohs(sockaddr_in->sin_port)); 213 } 214 215 /* If a hostname is numeric, there can't be a canonical name. 216 * Instead, the returned canonname (if requested) will be 217 * identical to the supplied hostname */ 218 if (nodename != NULL && nodename_numerical && 219 (flags & AI_CANONNAME)) { 220 if (strncmp(ai_cur->ai_canonname, nodename, 221 strlen(nodename))) 222 test_getaddrinfo_err(11, 223 TEST_GETADDRINFO_ERR_PARAMS, 224 nodename, ai_cur->ai_canonname); 225 } else { 226 /* is canonical supplied? */ 227 if (exp_canonname && nodename && 228 (!ai_cur->ai_canonname || !*ai_cur->ai_canonname)) 229 test_getaddrinfo_err(7, 230 TEST_GETADDRINFO_ERR_PARAMS, 231 "(anything)", ai_cur->ai_canonname); 232 233 if (!exp_canonname && ai_cur->ai_canonname) 234 test_getaddrinfo_err(8, 235 TEST_GETADDRINFO_ERR_PARAMS, 236 NULL, ai_cur->ai_canonname); 237 238 } 239 /* move to next result */ 240 ai_cur = ai_cur->ai_next; 241 } 242 243 /* If socket type is non-zero, make sure we got what we wanted. Else 244 * any result is okay. */ 245 if (socktype) { 246 if (ai_count_dgram != ((socktype == SOCK_STREAM) ? 0 : 1)) 247 test_getaddrinfo_err_nr(9, TEST_GETADDRINFO_ERR_PARAMS, 248 (socktype == SOCK_STREAM) ? 0 : 1, ai_count_dgram); 249 250 if (ai_count_stream != ((socktype == SOCK_DGRAM) ? 0 : 1)) 251 test_getaddrinfo_err_nr(10, TEST_GETADDRINFO_ERR_PARAMS, 252 (socktype == SOCK_DGRAM) ? 0 : 1, ai_count_stream); 253 } 254 255 /* clean up */ 256 freeaddrinfo(ai); 257 } 258 259 static void memsetl(void *s, unsigned long c, size_t n) 260 { 261 unsigned char *p = (unsigned char *) s; 262 size_t i; 263 264 for (i = 0; i < n; i++) 265 p[i] = c >> (8 * (i % sizeof(c))); 266 } 267 268 static void test_getnameinfo( 269 unsigned long ipaddr, 270 unsigned short port, 271 const char *exp_node, 272 socklen_t nodelen, 273 const char *exp_service, 274 socklen_t servicelen, 275 int flags, 276 int exp_results) 277 { 278 struct sockaddr_in sockaddr; 279 char node[256], service[256]; 280 int r; 281 282 /* avoid buffer overflows */ 283 assert(nodelen <= sizeof(node)); 284 assert(servicelen <= sizeof(service)); 285 286 /* perform query and test result */ 287 sockaddr.sin_family = AF_INET; 288 sockaddr.sin_addr.s_addr = ipaddr; 289 sockaddr.sin_port = port; 290 memsetl(node, 0xDEADBEEF, nodelen); 291 memsetl(service, 0xDEADBEEF, servicelen); 292 r = getnameinfo((struct sockaddr *) &sockaddr, sizeof(sockaddr), 293 node, nodelen, service, servicelen, flags); 294 295 if (r < 0 || r >= 32 || !((1 << r) & exp_results)) 296 test_getnameinfo_err_nr(1, TEST_GETNAMEINFO_ERR_PARAMS, 297 exp_results, r); 298 299 if (r) 300 return; 301 302 /* check results */ 303 if (nodelen && strcmp(exp_node, node) != 0) 304 test_getnameinfo_err(2, TEST_GETNAMEINFO_ERR_PARAMS, 305 exp_node, node); 306 307 if (servicelen && strcmp(exp_service, service) != 0) 308 test_getnameinfo_err(2, TEST_GETNAMEINFO_ERR_PARAMS, 309 exp_service, service); 310 } 311 312 static struct 313 { 314 const char *nodename; 315 unsigned long ipaddr; 316 int numeric; 317 int canonname; 318 int need_network; 319 int exp_result; 320 } hosts[] = { 321 { NULL, 0x7f000001, 1, 1, 0, 0 }, 322 { "0.0.0.0", 0x00000000, 1, 0, 0, 0 }, 323 { "0.0.0.255", 0x000000ff, 1, 0, 0, 0 }, 324 { "0.0.255.0", 0x0000ff00, 1, 0, 0, 0 }, 325 { "0.255.0.0", 0x00ff0000, 1, 0, 0, 0 }, 326 { "255.0.0.0", 0xff000000, 1, 0, 0, 0 }, 327 { "127.0.0.1", 0x7f000001, 1, 0, 0, 0 }, 328 { "localhost", 0x7f000001, 0, 1, 0, 0, }, 329 { "test48.minix3.org", 0x7f010203, 0, 1, 1, 0, }, 330 { "minix3.example.com", 0x00000000, 0, 0, 1, (1<<EAI_NONAME)|(1<<EAI_FAIL)|(1<<EAI_NODATA)}}; 331 332 static struct 333 { 334 const char *servname; 335 unsigned short port; 336 int numeric; 337 int socktype; 338 int exp_result; 339 } services[] = { 340 { NULL, 0, 1, 0, 0 }, 341 { "0", 0, 1, 0, 0 }, 342 { "1", 1, 1, 0, 0 }, 343 { "32767", 32767, 1, 0, 0 }, 344 { "32768", 32768, 1, 0, 0 }, 345 { "65535", 65535, 1, 0, 0 }, 346 { "echo", 7, 0, 0, 0 }, 347 { "ftp", 21, 0, 0, 0 }, 348 { "tftp", 69, 0, 0, 0 }, 349 { "-1", 0, 1, 0, (1<<EAI_NONAME) | (1<<EAI_SERVICE) }, 350 { "", 0, 1, 0, (1<<EAI_NONAME) | (1<<EAI_SERVICE) }, 351 { "65537", 0, 1, 0, (1 << EAI_SERVICE) }, 352 { "XXX", 0, 0, 0, (1 << EAI_SERVICE) }}; 353 354 static struct 355 { 356 int value; 357 int exp_result; 358 } families[] = { 359 { AF_UNSPEC, 0 }, 360 { AF_INET, 0 }, 361 { AF_UNSPEC + AF_INET + 1, (1 << EAI_FAMILY) }}; 362 363 static struct 364 { 365 int value; 366 int exp_result; 367 } socktypes[] = { 368 { 0, 0 }, 369 { SOCK_STREAM, 0 }, 370 { SOCK_DGRAM, 0 }, 371 { SOCK_STREAM + SOCK_DGRAM + 1, 372 (1 << EAI_SOCKTYPE) | (1 << EAI_FAIL) | (1 << EAI_NONAME) }}; 373 374 #define LENGTH(a) (sizeof((a)) / sizeof((a)[0])) 375 376 static void test_getaddrinfo_all(int use_network) 377 { 378 int flag_PASSIVE, flag_CANONNAME, flag_NUMERICHOST, flag_NUMERICSERV; 379 int exp_results, flags, flagcount, i, j, k, l, passhints; 380 unsigned long ipaddr; 381 382 /* loop through various parameter values */ 383 for (i = 0; i < LENGTH(hosts); i++) 384 for (j = 0; j < LENGTH(services); j++) 385 for (k = 0; k < LENGTH(families); k++) 386 for (l = 0; l < LENGTH(socktypes); l++) 387 for (flag_PASSIVE = 0; flag_PASSIVE < 2; flag_PASSIVE++) 388 for (flag_CANONNAME = 0; flag_CANONNAME < 2; flag_CANONNAME++) 389 for (flag_NUMERICHOST = 0; flag_NUMERICHOST < 2; flag_NUMERICHOST++) 390 for (flag_NUMERICSERV = 0; flag_NUMERICSERV < 2; flag_NUMERICSERV++) 391 for (passhints = 0; passhints < 2; passhints++) 392 { 393 /* skip some redundant combinations */ 394 flagcount = flag_PASSIVE + flag_CANONNAME + 395 flag_NUMERICHOST + flag_NUMERICSERV; 396 if (flagcount > 1 && flagcount < 4) continue; 397 398 /* skip tests that need but cannot use network */ 399 if (!use_network && hosts[i].need_network) 400 continue; 401 402 /* determine flags */ 403 flags = (flag_PASSIVE ? AI_PASSIVE : 0) | 404 (flag_CANONNAME ? AI_CANONNAME : 0) | 405 (flag_NUMERICHOST ? AI_NUMERICHOST : 0) | 406 (flag_NUMERICSERV ? AI_NUMERICSERV : 0); 407 408 /* some options require hints */ 409 if (families[k].value != AF_UNSPEC || 410 socktypes[l].value != 0 || flags) { 411 passhints = 1; 412 } 413 414 /* flags may influence IP address */ 415 ipaddr = hosts[i].ipaddr; 416 if (!hosts[i].nodename && flag_PASSIVE) 417 ipaddr = INADDR_ANY; 418 419 /* determine expected result */ 420 exp_results = 421 hosts[i].exp_result | 422 services[j].exp_result | 423 families[k].exp_result | 424 socktypes[l].exp_result; 425 if (!hosts[i].nodename && !services[j].servname) 426 exp_results |= (1 << EAI_NONAME); 427 428 if (flag_NUMERICHOST && !hosts[i].numeric) 429 exp_results |= (1 << EAI_NONAME); 430 431 if (flag_NUMERICSERV && !services[j].numeric) 432 exp_results |= (1 << EAI_NONAME); 433 434 /* When we don't pass hints, getaddrinfo will find suitable 435 * settings for us. If we do pass hints, there might be 436 * conflicts. 437 */ 438 if (passhints) { 439 /* Can't have conflicting socket types */ 440 if (services[j].socktype && 441 socktypes[l].value && 442 socktypes[l].value != services[j].socktype) { 443 exp_results |= (1 << EAI_SERVICE); 444 } 445 } 446 447 /* with no reason for failure, we demand success */ 448 if (!exp_results) 449 exp_results |= (1 << 0); 450 451 /* test getaddrinfo function */ 452 test_getaddrinfo( 453 hosts[i].nodename, 454 hosts[i].numeric, 455 services[j].servname, 456 services[j].numeric, 457 passhints, 458 flags, 459 families[k].value, 460 socktypes[l].value, 461 exp_results, 462 htonl(ipaddr), 463 flag_CANONNAME && hosts[i].canonname, 464 htons(services[j].port)); 465 } 466 } 467 468 static struct 469 { 470 const char *nodename; 471 const char *nodenum; 472 unsigned long ipaddr; 473 int havename; 474 } ipaddrs[] = { 475 { "0.0.0.0", "0.0.0.0", 0x00000000, 0 }, 476 { "0.0.0.255", "0.0.0.255", 0x000000ff, 0 }, 477 { "0.0.255.0", "0.0.255.0", 0x0000ff00, 0 }, 478 { "0.255.0.0", "0.255.0.0", 0x00ff0000, 0 }, 479 { "255.0.0.0", "255.0.0.0", 0xff000000, 0 }, 480 { "localhost", "127.0.0.1", 0x7f000001, 1 }, 481 /* no reverse DNS unfortunately */ 482 /* { "minix3.org", "130.37.20.20", 0x82251414, 1 } */}; 483 484 static struct 485 { 486 const char *servname; 487 const char *servnum; 488 unsigned short port; 489 int socktype; 490 struct servent *se_tcp; /* getservbyport() s_name on this port with "tcp" */ 491 struct servent *se_udp; /* getservbyport() s_name on this port with "udp" */ 492 } ports[] = { 493 { "0", "0", 0, 0 }, 494 { "tcpmux", "1", 1, SOCK_STREAM }, 495 { "32767", "32767", 32767, 0 }, 496 { "32768", "32768", 32768, 0 }, 497 { "65535", "65535", 65535, 0 }, 498 { "echo", "7", 7, 0 }, 499 { "ftp", "21", 21, SOCK_STREAM }, 500 { "tftp", "69", 69, SOCK_DGRAM }}; 501 502 static int buflens[] = { 0, 1, 2, 3, 4, 5, 6, 9, 10, 11, 255 }; 503 504 static void test_getnameinfo_all(void) 505 { 506 int flag_NUMERICHOST, flag_NAMEREQD, flag_NUMERICSERV, flag_DGRAM; 507 int exp_results, flagcount, flags, i, j, k, l; 508 const char *nodename, *servname; 509 510 /* set ports servent structs */ 511 for (j = 0; j < LENGTH(ports); j++) { 512 struct servent *se_tcp, *se_udp; 513 514 se_tcp = getservbyport(htons(ports[j].port), "tcp"); 515 ports[j].se_tcp = se_tcp; 516 517 if(ports[j].se_tcp) { 518 ports[j].se_tcp = malloc(sizeof(struct servent)); 519 memcpy(ports[j].se_tcp, se_tcp, sizeof(*se_tcp)); 520 assert(ports[j].se_tcp->s_name); 521 ports[j].se_tcp->s_name = strdup(ports[j].se_tcp->s_name); 522 assert(ports[j].se_tcp->s_name); 523 } 524 525 se_udp = getservbyport(htons(ports[j].port), "udp"); 526 ports[j].se_udp = se_udp; 527 528 if(ports[j].se_udp) { 529 ports[j].se_udp = malloc(sizeof(struct servent)); 530 memcpy(ports[j].se_udp, se_udp, sizeof(*se_udp)); 531 assert(ports[j].se_udp->s_name); 532 ports[j].se_udp->s_name = strdup(ports[j].se_udp->s_name); 533 assert(ports[j].se_udp->s_name); 534 } 535 } 536 537 /* loop through various parameter values */ 538 for (i = 0; i < LENGTH(ipaddrs); i++) 539 for (j = 0; j < LENGTH(ports); j++) 540 for (k = 0; k < LENGTH(buflens); k++) 541 for (l = 0; l < LENGTH(buflens); l++) 542 for (flag_NUMERICHOST = 0; flag_NUMERICHOST < 2; flag_NUMERICHOST++) 543 for (flag_NAMEREQD = 0; flag_NAMEREQD < 2; flag_NAMEREQD++) 544 for (flag_NUMERICSERV = 0; flag_NUMERICSERV < 2; flag_NUMERICSERV++) 545 for (flag_DGRAM = 0; flag_DGRAM < 2; flag_DGRAM++) 546 { 547 /* skip some redundant combinations */ 548 flagcount = flag_NUMERICHOST + flag_NAMEREQD + 549 flag_NUMERICSERV + flag_DGRAM; 550 if (flagcount > 1 && flagcount < 4) continue; 551 if (k > 1 && k < LENGTH(buflens) - 2 && 552 l > 1 && l < LENGTH(buflens) - 2) continue; 553 554 /* determine flags */ 555 flags = (flag_NUMERICHOST ? NI_NUMERICHOST : 0) | 556 (flag_NAMEREQD ? NI_NAMEREQD : 0) | 557 (flag_NUMERICSERV ? NI_NUMERICSERV : 0) | 558 (flag_DGRAM ? NI_DGRAM : 0); 559 560 /* determine expected result */ 561 exp_results = 0; 562 563 nodename = flag_NUMERICHOST ? ipaddrs[i].nodenum : ipaddrs[i].nodename; 564 if (buflens[k] > 0 && buflens[k] <= strlen(nodename)) 565 exp_results |= (1 << EAI_OVERFLOW) | (1 << EAI_MEMORY); 566 567 struct servent *se = flag_DGRAM ? ports[j].se_udp : ports[j].se_tcp; 568 569 servname = (flag_NUMERICSERV) ? 570 ports[j].servnum : (se ? se->s_name : ports[j].servname); 571 572 if (buflens[l] > 0 && buflens[l] <= strlen(servname)) 573 exp_results |= (1 << EAI_OVERFLOW) | (1 << EAI_MEMORY); 574 575 if (flag_NAMEREQD && (!ipaddrs[i].havename || flag_NUMERICHOST) && buflens[k]) 576 exp_results |= (1 << EAI_NONAME); 577 578 /* with no reason for failure, we demand success */ 579 if (!exp_results) 580 exp_results |= (1 << 0); 581 582 /* perform the test */ 583 test_getnameinfo( 584 htonl(ipaddrs[i].ipaddr), 585 htons(ports[j].port), 586 nodename, 587 buflens[k], 588 servname, 589 buflens[l], 590 flags, 591 exp_results); 592 } 593 } 594 595 int main(void) 596 { 597 int use_network; 598 599 start(48); 600 601 use_network = get_setting_use_network(); 602 test_getaddrinfo_all(use_network); 603 test_getnameinfo_all(); 604 605 quit(); 606 return 0; 607 } 608