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 /* test result fields */ 169 if (ai_cur->ai_family != AF_INET) 170 test_getaddrinfo_err_nr(2, TEST_GETADDRINFO_ERR_PARAMS, 171 AF_INET, ai_cur->ai_family); 172 173 if (socktype && ai_cur->ai_socktype != socktype) 174 test_getaddrinfo_err_nr(3, TEST_GETADDRINFO_ERR_PARAMS, 175 socktype, ai_cur->ai_socktype); 176 177 switch (ai_cur->ai_socktype) 178 { 179 case SOCK_DGRAM: ai_count_dgram++; break; 180 case SOCK_STREAM: ai_count_stream++; break; 181 } 182 183 /* do address and port match? */ 184 if (ai_cur->ai_addrlen != sizeof(struct sockaddr_in)) 185 test_getaddrinfo_err_nr(4, TEST_GETADDRINFO_ERR_PARAMS, 186 sizeof(struct sockaddr_in), 187 ai_cur->ai_addrlen); 188 else 189 { 190 sockaddr_in = (struct sockaddr_in *) ai_cur->ai_addr; 191 if (sockaddr_in->sin_addr.s_addr != exp_ip) 192 test_getaddrinfo_err_nr(5, 193 TEST_GETADDRINFO_ERR_PARAMS, 194 ntohl(exp_ip), 195 ntohl(sockaddr_in->sin_addr.s_addr)); 196 197 if (sockaddr_in->sin_port != exp_port) 198 test_getaddrinfo_err_nr(6, 199 TEST_GETADDRINFO_ERR_PARAMS, 200 ntohs(exp_port), 201 ntohs(sockaddr_in->sin_port)); 202 } 203 204 /* If a hostname is numeric, there can't be a canonical name. 205 * Instead, the returned canonname (if requested) will be 206 * identical to the supplied hostname */ 207 if (nodename != NULL && nodename_numerical && 208 (flags & AI_CANONNAME)) { 209 if (strncmp(ai_cur->ai_canonname, nodename, 210 strlen(nodename))) 211 test_getaddrinfo_err(11, 212 TEST_GETADDRINFO_ERR_PARAMS, 213 nodename, ai_cur->ai_canonname); 214 } else { 215 /* is canonical supplied? */ 216 if (exp_canonname && nodename && 217 (!ai_cur->ai_canonname || !*ai_cur->ai_canonname)) 218 test_getaddrinfo_err(7, 219 TEST_GETADDRINFO_ERR_PARAMS, 220 "(anything)", ai_cur->ai_canonname); 221 222 if (!exp_canonname && ai_cur->ai_canonname) 223 test_getaddrinfo_err(8, 224 TEST_GETADDRINFO_ERR_PARAMS, 225 NULL, ai_cur->ai_canonname); 226 227 } 228 /* move to next result */ 229 ai_cur = ai_cur->ai_next; 230 } 231 232 /* If socket type is non-zero, make sure we got what we wanted. Else 233 * any result is okay. */ 234 if (socktype) { 235 if (ai_count_dgram != ((socktype == SOCK_STREAM) ? 0 : 1)) 236 test_getaddrinfo_err_nr(9, TEST_GETADDRINFO_ERR_PARAMS, 237 (socktype == SOCK_STREAM) ? 0 : 1, ai_count_dgram); 238 239 if (ai_count_stream != ((socktype == SOCK_DGRAM) ? 0 : 1)) 240 test_getaddrinfo_err_nr(10, TEST_GETADDRINFO_ERR_PARAMS, 241 (socktype == SOCK_DGRAM) ? 0 : 1, ai_count_stream); 242 } 243 244 /* clean up */ 245 freeaddrinfo(ai); 246 } 247 248 static void memsetl(void *s, unsigned long c, size_t n) 249 { 250 unsigned char *p = (unsigned char *) s; 251 size_t i; 252 253 for (i = 0; i < n; i++) 254 p[i] = c >> (8 * (i % sizeof(c))); 255 } 256 257 static void test_getnameinfo( 258 unsigned long ipaddr, 259 unsigned short port, 260 const char *exp_node, 261 socklen_t nodelen, 262 const char *exp_service, 263 socklen_t servicelen, 264 int flags, 265 int exp_results) 266 { 267 struct sockaddr_in sockaddr; 268 char node[256], service[256]; 269 int r; 270 271 /* avoid buffer overflows */ 272 assert(nodelen <= sizeof(node)); 273 assert(servicelen <= sizeof(service)); 274 275 /* perform query and test result */ 276 sockaddr.sin_family = AF_INET; 277 sockaddr.sin_addr.s_addr = ipaddr; 278 sockaddr.sin_port = port; 279 memsetl(node, 0xDEADBEEF, nodelen); 280 memsetl(service, 0xDEADBEEF, servicelen); 281 r = getnameinfo((struct sockaddr *) &sockaddr, sizeof(sockaddr), 282 node, nodelen, service, servicelen, flags); 283 284 if (r < 0 || r >= 32 || !((1 << r) & exp_results)) 285 test_getnameinfo_err_nr(1, TEST_GETNAMEINFO_ERR_PARAMS, 286 exp_results, r); 287 288 if (r) 289 return; 290 291 /* check results */ 292 if (nodelen && strcmp(exp_node, node) != 0) 293 test_getnameinfo_err(2, TEST_GETNAMEINFO_ERR_PARAMS, 294 exp_node, node); 295 296 if (servicelen && strcmp(exp_service, service) != 0) 297 test_getnameinfo_err(2, TEST_GETNAMEINFO_ERR_PARAMS, 298 exp_service, service); 299 } 300 301 static struct 302 { 303 const char *nodename; 304 unsigned long ipaddr; 305 int numeric; 306 int canonname; 307 int need_network; 308 int exp_result; 309 } hosts[] = { 310 { NULL, 0x7f000001, 1, 1, 0, 0 }, 311 { "0.0.0.0", 0x00000000, 1, 0, 0, 0 }, 312 { "0.0.0.255", 0x000000ff, 1, 0, 0, 0 }, 313 { "0.0.255.0", 0x0000ff00, 1, 0, 0, 0 }, 314 { "0.255.0.0", 0x00ff0000, 1, 0, 0, 0 }, 315 { "255.0.0.0", 0xff000000, 1, 0, 0, 0 }, 316 { "127.0.0.1", 0x7f000001, 1, 0, 0, 0 }, 317 { "localhost", 0x7f000001, 0, 1, 0, 0, }, 318 { "test48.minix3.org", 0x7f010203, 0, 1, 1, 0, }, 319 { "", 0x00000000, 1, 0, 0, (1<<EAI_NONAME)|(1<<EAI_FAIL)|(1<<EAI_NODATA)}, 320 { "256.256.256.256",0x00000000, 1, 0, 0, (1<<EAI_NONAME)|(1<<EAI_FAIL)|(1<<EAI_NODATA)}, 321 { "minix3.example.com", 0x00000000, 0, 0, 1, (1<<EAI_NONAME)|(1<<EAI_FAIL)|(1<<EAI_NODATA)}}; 322 323 static struct 324 { 325 const char *servname; 326 unsigned short port; 327 int numeric; 328 int socktype; 329 int exp_result; 330 } services[] = { 331 { NULL, 0, 1, 0, 0 }, 332 { "0", 0, 1, 0, 0 }, 333 { "1", 1, 1, 0, 0 }, 334 { "32767", 32767, 1, 0, 0 }, 335 { "32768", 32768, 1, 0, 0 }, 336 { "65535", 65535, 1, 0, 0 }, 337 { "echo", 7, 0, 0, 0 }, 338 { "ftp", 21, 0, 0, 0 }, 339 { "tftp", 69, 0, 0, 0 }, 340 { "-1", 0, 1, 0, (1<<EAI_NONAME) | (1<<EAI_SERVICE) }, 341 { "", 0, 1, 0, (1<<EAI_NONAME) | (1<<EAI_SERVICE) }, 342 { "65537", 0, 1, 0, (1 << EAI_SERVICE) }, 343 { "XXX", 0, 0, 0, (1 << EAI_SERVICE) }}; 344 345 static struct 346 { 347 int value; 348 int exp_result; 349 } families[] = { 350 { AF_UNSPEC, 0 }, 351 { AF_INET, 0 }, 352 { AF_UNSPEC + AF_INET + 1, (1 << EAI_FAMILY) }}; 353 354 static struct 355 { 356 int value; 357 int exp_result; 358 } socktypes[] = { 359 { 0, 0 }, 360 { SOCK_STREAM, 0 }, 361 { SOCK_DGRAM, 0 }, 362 { SOCK_STREAM + SOCK_DGRAM + 1, 363 (1 << EAI_SOCKTYPE) | (1 << EAI_FAIL) | (1 << EAI_NONAME) }}; 364 365 #define LENGTH(a) (sizeof((a)) / sizeof((a)[0])) 366 367 static void test_getaddrinfo_all(int use_network) 368 { 369 int flag_PASSIVE, flag_CANONNAME, flag_NUMERICHOST, flag_NUMERICSERV; 370 int exp_results, flags, flagcount, i, j, k, l, passhints; 371 unsigned long ipaddr; 372 373 /* loop through various parameter values */ 374 for (i = 0; i < LENGTH(hosts); i++) 375 for (j = 0; j < LENGTH(services); j++) 376 for (k = 0; k < LENGTH(families); k++) 377 for (l = 0; l < LENGTH(socktypes); l++) 378 for (flag_PASSIVE = 0; flag_PASSIVE < 2; flag_PASSIVE++) 379 for (flag_CANONNAME = 0; flag_CANONNAME < 2; flag_CANONNAME++) 380 for (flag_NUMERICHOST = 0; flag_NUMERICHOST < 2; flag_NUMERICHOST++) 381 for (flag_NUMERICSERV = 0; flag_NUMERICSERV < 2; flag_NUMERICSERV++) 382 for (passhints = 0; passhints < 2; passhints++) 383 { 384 /* skip some redundant combinations */ 385 flagcount = flag_PASSIVE + flag_CANONNAME + 386 flag_NUMERICHOST + flag_NUMERICSERV; 387 if (flagcount > 1 && flagcount < 4) continue; 388 389 /* skip tests that need but cannot use network */ 390 if (!use_network && hosts[i].need_network) 391 continue; 392 393 /* determine flags */ 394 flags = (flag_PASSIVE ? AI_PASSIVE : 0) | 395 (flag_CANONNAME ? AI_CANONNAME : 0) | 396 (flag_NUMERICHOST ? AI_NUMERICHOST : 0) | 397 (flag_NUMERICSERV ? AI_NUMERICSERV : 0); 398 399 /* some options require hints */ 400 if (families[k].value != AF_UNSPEC || 401 socktypes[l].value != 0 || flags) { 402 passhints = 1; 403 } 404 405 /* flags may influence IP address */ 406 ipaddr = hosts[i].ipaddr; 407 if (!hosts[i].nodename && flag_PASSIVE) 408 ipaddr = INADDR_ANY; 409 410 /* determine expected result */ 411 exp_results = 412 hosts[i].exp_result | 413 services[j].exp_result | 414 families[k].exp_result | 415 socktypes[l].exp_result; 416 if (!hosts[i].nodename && !services[j].servname) 417 exp_results |= (1 << EAI_NONAME); 418 419 if (flag_NUMERICHOST && !hosts[i].numeric) 420 exp_results |= (1 << EAI_NONAME); 421 422 if (flag_NUMERICSERV && !services[j].numeric) 423 exp_results |= (1 << EAI_NONAME); 424 425 /* When we don't pass hints, getaddrinfo will find suitable 426 * settings for us. If we do pass hints, there might be 427 * conflicts. 428 */ 429 if (passhints) { 430 /* Can't have conflicting socket types */ 431 if (services[j].socktype && 432 socktypes[l].value && 433 socktypes[l].value != services[j].socktype) { 434 exp_results |= (1 << EAI_SERVICE); 435 } 436 } 437 438 /* with no reason for failure, we demand success */ 439 if (!exp_results) 440 exp_results |= (1 << 0); 441 442 /* test getaddrinfo function */ 443 test_getaddrinfo( 444 hosts[i].nodename, 445 hosts[i].numeric, 446 services[j].servname, 447 services[j].numeric, 448 passhints, 449 flags, 450 families[k].value, 451 socktypes[l].value, 452 exp_results, 453 htonl(ipaddr), 454 flag_CANONNAME && hosts[i].canonname, 455 htons(services[j].port)); 456 } 457 } 458 459 static struct 460 { 461 const char *nodename; 462 const char *nodenum; 463 unsigned long ipaddr; 464 int havename; 465 } ipaddrs[] = { 466 { "0.0.0.0", "0.0.0.0", 0x00000000, 0 }, 467 { "0.0.0.255", "0.0.0.255", 0x000000ff, 0 }, 468 { "0.0.255.0", "0.0.255.0", 0x0000ff00, 0 }, 469 { "0.255.0.0", "0.255.0.0", 0x00ff0000, 0 }, 470 { "255.0.0.0", "255.0.0.0", 0xff000000, 0 }, 471 { "localhost", "127.0.0.1", 0x7f000001, 1 }, 472 /* no reverse DNS unfortunately */ 473 /* { "minix3.org", "130.37.20.20", 0x82251414, 1 } */}; 474 475 static struct 476 { 477 const char *servname; 478 const char *servnum; 479 unsigned short port; 480 int socktype; 481 struct servent *se_tcp; /* getservbyport() s_name on this port with "tcp" */ 482 struct servent *se_udp; /* getservbyport() s_name on this port with "udp" */ 483 } ports[] = { 484 { "0", "0", 0, 0 }, 485 { "tcpmux", "1", 1, SOCK_STREAM }, 486 { "32767", "32767", 32767, 0 }, 487 { "32768", "32768", 32768, 0 }, 488 { "65535", "65535", 65535, 0 }, 489 { "echo", "7", 7, 0 }, 490 { "ftp", "21", 21, SOCK_STREAM }, 491 { "tftp", "69", 69, SOCK_DGRAM }}; 492 493 static int buflens[] = { 0, 1, 2, 3, 4, 5, 6, 9, 10, 11, 255 }; 494 495 static void test_getnameinfo_all(void) 496 { 497 int flag_NUMERICHOST, flag_NAMEREQD, flag_NUMERICSERV, flag_DGRAM; 498 int exp_results, flagcount, flags, i, j, k, l; 499 const char *nodename, *servname; 500 501 /* set ports servent structs */ 502 for (j = 0; j < LENGTH(ports); j++) { 503 struct servent *se_tcp, *se_udp; 504 505 se_tcp = getservbyport(htons(ports[j].port), "tcp"); 506 ports[j].se_tcp = se_tcp; 507 508 if(ports[j].se_tcp) { 509 ports[j].se_tcp = malloc(sizeof(struct servent)); 510 memcpy(ports[j].se_tcp, se_tcp, sizeof(*se_tcp)); 511 assert(ports[j].se_tcp->s_name); 512 ports[j].se_tcp->s_name = strdup(ports[j].se_tcp->s_name); 513 assert(ports[j].se_tcp->s_name); 514 } 515 516 se_udp = getservbyport(htons(ports[j].port), "udp"); 517 ports[j].se_udp = se_udp; 518 519 if(ports[j].se_udp) { 520 ports[j].se_udp = malloc(sizeof(struct servent)); 521 memcpy(ports[j].se_udp, se_udp, sizeof(*se_udp)); 522 assert(ports[j].se_udp->s_name); 523 ports[j].se_udp->s_name = strdup(ports[j].se_udp->s_name); 524 assert(ports[j].se_udp->s_name); 525 } 526 } 527 528 /* loop through various parameter values */ 529 for (i = 0; i < LENGTH(ipaddrs); i++) 530 for (j = 0; j < LENGTH(ports); j++) 531 for (k = 0; k < LENGTH(buflens); k++) 532 for (l = 0; l < LENGTH(buflens); l++) 533 for (flag_NUMERICHOST = 0; flag_NUMERICHOST < 2; flag_NUMERICHOST++) 534 for (flag_NAMEREQD = 0; flag_NAMEREQD < 2; flag_NAMEREQD++) 535 for (flag_NUMERICSERV = 0; flag_NUMERICSERV < 2; flag_NUMERICSERV++) 536 for (flag_DGRAM = 0; flag_DGRAM < 2; flag_DGRAM++) 537 { 538 /* skip some redundant combinations */ 539 flagcount = flag_NUMERICHOST + flag_NAMEREQD + 540 flag_NUMERICSERV + flag_DGRAM; 541 if (flagcount > 1 && flagcount < 4) continue; 542 if (k > 1 && k < LENGTH(buflens) - 2 && 543 l > 1 && l < LENGTH(buflens) - 2) continue; 544 545 /* determine flags */ 546 flags = (flag_NUMERICHOST ? NI_NUMERICHOST : 0) | 547 (flag_NAMEREQD ? NI_NAMEREQD : 0) | 548 (flag_NUMERICSERV ? NI_NUMERICSERV : 0) | 549 (flag_DGRAM ? NI_DGRAM : 0); 550 551 /* determine expected result */ 552 exp_results = 0; 553 554 nodename = flag_NUMERICHOST ? ipaddrs[i].nodenum : ipaddrs[i].nodename; 555 if (buflens[k] > 0 && buflens[k] <= strlen(nodename)) 556 exp_results |= (1 << EAI_OVERFLOW) | (1 << EAI_MEMORY); 557 558 struct servent *se = flag_DGRAM ? ports[j].se_udp : ports[j].se_tcp; 559 560 servname = (flag_NUMERICSERV) ? 561 ports[j].servnum : (se ? se->s_name : ports[j].servname); 562 563 if (buflens[l] > 0 && buflens[l] <= strlen(servname)) 564 exp_results |= (1 << EAI_OVERFLOW) | (1 << EAI_MEMORY); 565 566 if (flag_NAMEREQD && (!ipaddrs[i].havename || flag_NUMERICHOST) && buflens[k]) 567 exp_results |= (1 << EAI_NONAME); 568 569 /* with no reason for failure, we demand success */ 570 if (!exp_results) 571 exp_results |= (1 << 0); 572 573 /* perform the test */ 574 test_getnameinfo( 575 htonl(ipaddrs[i].ipaddr), 576 htons(ports[j].port), 577 nodename, 578 buflens[k], 579 servname, 580 buflens[l], 581 flags, 582 exp_results); 583 } 584 } 585 586 int main(void) 587 { 588 int use_network; 589 590 start(48); 591 592 use_network = get_setting_use_network(); 593 test_getaddrinfo_all(use_network); 594 test_getnameinfo_all(); 595 596 quit(); 597 return 0; 598 } 599