1 /* 2 * Copyright (c) 2001, 02 Motoyuki Kasahara 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 * 3. Neither the name of the project nor the names of its contributors 13 * may be used to endorse or promote products derived from this software 14 * without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * This program provides getaddrinfo() and getnameinfo() described in 31 * RFC2133, 2553 and 3493. These functions are mainly used for IPv6 32 * application to resolve hostname or address. 33 * 34 * This program is designed to be working on traditional IPv4 systems 35 * which don't have those functions. Therefore, this implementation 36 * supports IPv4 only. 37 * 38 * This program is useful for application which should support both IPv6 39 * and traditional IPv4 systems. Use genuine getaddrinfo() and getnameinfo() 40 * provided by system if the system supports IPv6. Otherwise, use this 41 * implementation. 42 * 43 * This program is intended to be used in combination with GNU Autoconf. 44 * 45 * This program also provides freeaddrinfo() and gai_strerror(). 46 * 47 * To use this program in your application, insert the following lines to 48 * C source files after including `sys/types.h', `sys/socket.h' and 49 * `netdb.h'. `getaddrinfo.h' defines `struct addrinfo' and AI_, NI_, 50 * EAI_ macros. 51 * 52 * #ifndef HAVE_GETADDRINFO 53 * #include "getaddrinfo.h" 54 * #endif 55 * 56 * Restriction: 57 * getaddrinfo() and getnameinfo() of this program are NOT thread 58 * safe, unless the cpp macro ENABLE_PTHREAD is defined. 59 */ 60 61 /* 62 * Add the following code to your configure.ac (or configure.in). 63 * AC_C_CONST 64 * AC_HEADER_STDC 65 * AC_CHECK_HEADERS(string.h memory.h stdlib.h) 66 * AC_CHECK_FUNCS(memcpy) 67 * AC_REPLACE_FUNCS(memset) 68 * AC_TYPE_SOCKLEN_T 69 * AC_TYPE_IN_PORT_T 70 * AC_DECL_H_ERRNO 71 * 72 * AC_CHECK_FUNCS(getaddrinfo getnameinfo) 73 * if test "$ac_cv_func_getaddrinfo$ac_cv_func_getnameinfo" != yesyes ; then 74 * LIBOBJS="$LIBOBJS getaddrinfo.$ac_objext" 75 * fi 76 */ 77 78 #ifdef HAVE_CONFIG_H 79 #include "config.h" 80 #endif 81 82 #include <sys/types.h> 83 #include <stdio.h> 84 85 #ifdef WIN32 86 #include <time.h> 87 #include <winsock2.h> 88 #ifdef DO_IPV6 89 #include <ws2tcpip.h> 90 #endif /* DO_IPV6 */ 91 #include <windows.h> 92 #else 93 #include <sys/socket.h> 94 #endif 95 96 97 #include <netinet/in.h> 98 #include <arpa/inet.h> 99 #include <netdb.h> 100 101 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H) 102 #include <string.h> 103 #if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H) 104 #include <memory.h> 105 #endif /* not STDC_HEADERS and HAVE_MEMORY_H */ 106 #else /* not STDC_HEADERS and not HAVE_STRING_H */ 107 #include <strings.h> 108 #endif /* not STDC_HEADERS and not HAVE_STRING_H */ 109 110 #ifdef HAVE_STDLIB_H 111 #include <stdlib.h> 112 #endif 113 114 #ifdef ENABLE_PTHREAD 115 #include <pthread.h> 116 #endif 117 118 #ifdef ENABLE_NLS 119 #include <libintl.h> 120 #endif 121 122 #ifndef HAVE_MEMCPY 123 #define memcpy(d, s, n) bcopy((s), (d), (n)) 124 #ifdef __STDC__ 125 void *memchr(const void *, int, size_t); 126 int memcmp(const void *, const void *, size_t); 127 void *memmove(void *, const void *, size_t); 128 void *memset(void *, int, size_t); 129 #else /* not __STDC__ */ 130 char *memchr(); 131 int memcmp(); 132 char *memmove(); 133 char *memset(); 134 #endif /* not __STDC__ */ 135 #endif /* not HAVE_MEMCPY */ 136 137 #ifndef H_ERRNO_DECLARED 138 extern int h_errno; 139 #endif 140 141 #include "getaddrinfo.h" 142 143 #ifdef ENABLE_NLS 144 #define _(string) gettext(string) 145 #ifdef gettext_noop 146 #define N_(string) gettext_noop(string) 147 #else 148 #define N_(string) (string) 149 #endif 150 #else 151 #define gettext(string) (string) 152 #define _(string) (string) 153 #define N_(string) (string) 154 #endif 155 156 /* 157 * Error messages for gai_strerror(). 158 */ 159 static char *eai_errlist[] = { 160 N_("Success"), 161 162 /* EAI_ADDRFAMILY */ 163 N_("Address family for hostname not supported"), 164 165 /* EAI_AGAIN */ 166 N_("Temporary failure in name resolution"), 167 168 /* EAI_BADFLAGS */ 169 N_("Invalid value for ai_flags"), 170 171 /* EAI_FAIL */ 172 N_("Non-recoverable failure in name resolution"), 173 174 /* EAI_FAMILY */ 175 N_("ai_family not supported"), 176 177 /* EAI_MEMORY */ 178 N_("Memory allocation failure"), 179 180 /* EAI_NONAME */ 181 N_("hostname nor servname provided, or not known"), 182 183 /* EAI_OVERFLOW */ 184 N_("An argument buffer overflowed"), 185 186 /* EAI_SERVICE */ 187 N_("servname not supported for ai_socktype"), 188 189 /* EAI_SOCKTYPE */ 190 N_("ai_socktype not supported"), 191 192 /* EAI_SYSTEM */ 193 N_("System error returned in errno") 194 }; 195 196 /* 197 * Default hints for getaddrinfo(). 198 */ 199 static struct addrinfo default_hints = { 200 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL 201 }; 202 203 /* 204 * Mutex. 205 */ 206 #ifdef ENABLE_PTHREAD 207 static pthread_mutex_t gai_mutex = PTHREAD_MUTEX_INITIALIZER; 208 #endif 209 210 /* 211 * Declaration of static functions. 212 */ 213 #ifdef __STDC__ 214 static int is_integer(const char *); 215 static int is_address(const char *); 216 static int itoa_length(int); 217 #else 218 static int is_integer(); 219 static int is_address(); 220 static int itoa_length(); 221 #endif 222 223 /* 224 * gai_strerror(). 225 */ 226 const char * 227 gai_strerror(ecode) 228 int ecode; 229 { 230 if (ecode < 0 || ecode > EAI_SYSTEM) 231 return _("Unknown error"); 232 233 return gettext(eai_errlist[ecode]); 234 } 235 236 /* 237 * freeaddrinfo(). 238 */ 239 void 240 freeaddrinfo(ai) 241 struct addrinfo *ai; 242 { 243 struct addrinfo *next_ai; 244 245 while (ai != NULL) { 246 if (ai->ai_canonname != NULL) 247 free(ai->ai_canonname); 248 if (ai->ai_addr != NULL) 249 free(ai->ai_addr); 250 next_ai = ai->ai_next; 251 free(ai); 252 ai = next_ai; 253 } 254 } 255 256 /* 257 * Return 1 if the string `s' represents an integer. 258 */ 259 static int 260 is_integer(s) 261 const char *s; 262 { 263 if (*s == '-' || *s == '+') 264 s++; 265 if (*s < '0' || '9' < *s) 266 return 0; 267 268 s++; 269 while ('0' <= *s && *s <= '9') 270 s++; 271 272 return (*s == '\0'); 273 } 274 275 /* 276 * Return 1 if the string `s' represents an IPv4 address. 277 * Unlike inet_addr(), it doesn't permit malformed nortation such 278 * as "192.168". 279 */ 280 static int 281 is_address(s) 282 const char *s; 283 { 284 const static char delimiters[] = {'.', '.', '.', '\0'}; 285 int i, j; 286 int octet; 287 288 for (i = 0; i < 4; i++) { 289 if (*s == '0' && *(s + 1) != delimiters[i]) 290 return 0; 291 for (j = 0, octet = 0; '0' <= *s && *s <= '9' && j < 3; s++, j++) 292 octet = octet * 10 + (*s - '0'); 293 if (j == 0 || octet > 255 || *s != delimiters[i]) 294 return 0; 295 s++; 296 } 297 298 return 1; 299 } 300 301 /* 302 * Calcurate length of the string `s', where `s' is set by 303 * sprintf(s, "%d", n). 304 */ 305 static int 306 itoa_length(n) 307 int n; 308 { 309 int result = 1; 310 311 if (n < 0) { 312 n = -n; 313 result++; 314 } 315 316 while (n >= 10) { 317 result++; 318 n /= 10; 319 } 320 321 return result; 322 } 323 324 /* 325 * getaddrinfo(). 326 */ 327 int 328 getaddrinfo(nodename, servname, hints, res) 329 const char *nodename; 330 const char *servname; 331 const struct addrinfo *hints; 332 struct addrinfo **res; 333 { 334 struct addrinfo *head_res = NULL; 335 struct addrinfo *tail_res = NULL; 336 struct addrinfo *new_res; 337 struct sockaddr_in *sa_in; 338 struct in_addr **addr_list; 339 struct in_addr *addr_list_buf[2]; 340 struct in_addr addr_buf; 341 struct in_addr **ap; 342 struct servent *servent; 343 struct hostent *hostent; 344 const char *canonname = NULL; 345 in_port_t port; 346 int saved_h_errno; 347 int result = 0; 348 349 #ifdef ENABLE_PTHREAD 350 pthread_mutex_lock(&gai_mutex); 351 #endif 352 353 saved_h_errno = h_errno; 354 355 if (nodename == NULL && servname == NULL) { 356 result = EAI_NONAME; 357 goto end; 358 } 359 360 if (hints != NULL) { 361 if (hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC) { 362 result = EAI_FAMILY; 363 goto end; 364 } 365 if (hints->ai_socktype != SOCK_DGRAM 366 && hints->ai_socktype != SOCK_STREAM 367 && hints->ai_socktype != 0) { 368 result = EAI_SOCKTYPE; 369 goto end; 370 } 371 } else { 372 hints = &default_hints; 373 } 374 375 if (servname != NULL) { 376 if (is_integer(servname)) 377 port = htons(atoi(servname)); 378 else { 379 if (hints->ai_flags & AI_NUMERICSERV) { 380 result = EAI_NONAME; 381 goto end; 382 } 383 384 if (hints->ai_socktype == SOCK_DGRAM) 385 servent = getservbyname(servname, "udp"); 386 else if (hints->ai_socktype == SOCK_STREAM) 387 servent = getservbyname(servname, "tcp"); 388 else if (hints->ai_socktype == 0) 389 servent = getservbyname(servname, "tcp"); 390 else { 391 result = EAI_SOCKTYPE; 392 goto end; 393 } 394 395 if (servent == NULL) { 396 result = EAI_SERVICE; 397 goto end; 398 } 399 port = servent->s_port; 400 } 401 } else { 402 port = htons(0); 403 } 404 405 if (nodename != NULL) { 406 if (is_address(nodename)) { 407 addr_buf.s_addr = inet_addr(nodename); 408 addr_list_buf[0] = &addr_buf; 409 addr_list_buf[1] = NULL; 410 addr_list = addr_list_buf; 411 412 if (hints->ai_flags & AI_CANONNAME 413 && !(hints->ai_flags & AI_NUMERICHOST)) { 414 hostent = gethostbyaddr((char *)&addr_buf, 415 sizeof(struct in_addr), AF_INET); 416 if (hostent != NULL) 417 canonname = hostent->h_name; 418 else 419 canonname = nodename; 420 } 421 } else { 422 if (hints->ai_flags & AI_NUMERICHOST) { 423 result = EAI_NONAME; 424 goto end; 425 } 426 427 hostent = gethostbyname(nodename); 428 if (hostent == NULL) { 429 switch (h_errno) { 430 case HOST_NOT_FOUND: 431 case NO_DATA: 432 result = EAI_NONAME; 433 goto end; 434 case TRY_AGAIN: 435 result = EAI_AGAIN; 436 goto end; 437 default: 438 result = EAI_FAIL; 439 goto end; 440 } 441 } 442 addr_list = (struct in_addr **)hostent->h_addr_list; 443 444 if (hints->ai_flags & AI_CANONNAME) 445 canonname = hostent->h_name; 446 } 447 } else { 448 if (hints->ai_flags & AI_PASSIVE) 449 addr_buf.s_addr = htonl(INADDR_ANY); 450 else 451 addr_buf.s_addr = htonl(0x7F000001); 452 addr_list_buf[0] = &addr_buf; 453 addr_list_buf[1] = NULL; 454 addr_list = addr_list_buf; 455 } 456 457 for (ap = addr_list; *ap != NULL; ap++) { 458 new_res = (struct addrinfo *)malloc(sizeof(struct addrinfo)); 459 if (new_res == NULL) { 460 if (head_res != NULL) 461 freeaddrinfo(head_res); 462 result = EAI_MEMORY; 463 goto end; 464 } 465 466 new_res->ai_family = PF_INET; 467 new_res->ai_socktype = hints->ai_socktype; 468 new_res->ai_protocol = hints->ai_protocol; 469 new_res->ai_addr = NULL; 470 new_res->ai_addrlen = sizeof(struct sockaddr_in); 471 new_res->ai_canonname = NULL; 472 new_res->ai_next = NULL; 473 474 new_res->ai_addr = (struct sockaddr *) 475 malloc(sizeof(struct sockaddr_in)); 476 if (new_res->ai_addr == NULL) { 477 free(new_res); 478 if (head_res != NULL) 479 freeaddrinfo(head_res); 480 result = EAI_MEMORY; 481 goto end; 482 } 483 484 sa_in = (struct sockaddr_in *)new_res->ai_addr; 485 memset(sa_in, 0, sizeof(struct sockaddr_in)); 486 sa_in->sin_family = PF_INET; 487 sa_in->sin_port = port; 488 memcpy(&sa_in->sin_addr, *ap, sizeof(struct in_addr)); 489 490 if (head_res == NULL) 491 head_res = new_res; 492 else 493 tail_res->ai_next = new_res; 494 tail_res = new_res; 495 } 496 497 if (canonname != NULL && head_res != NULL) { 498 head_res->ai_canonname = (char *)malloc(strlen(canonname) + 1); 499 if (head_res->ai_canonname != NULL) 500 strcpy(head_res->ai_canonname, canonname); 501 } 502 503 *res = head_res; 504 505 end: 506 h_errno = saved_h_errno; 507 #ifdef ENABLE_PTHREAD 508 pthread_mutex_unlock(&gai_mutex); 509 #endif 510 return result; 511 } 512 513 /* 514 * getnameinfo(). 515 */ 516 int 517 getnameinfo(sa, salen, node, nodelen, serv, servlen, flags) 518 const struct sockaddr *sa; 519 socklen_t salen; 520 char *node; 521 socklen_t nodelen; 522 char *serv; 523 socklen_t servlen; 524 int flags; 525 { 526 const struct sockaddr_in *sa_in = (const struct sockaddr_in *)sa; 527 struct hostent *hostent; 528 struct servent *servent; 529 char *ntoa_address; 530 int saved_h_errno; 531 int result = 0; 532 533 #ifdef ENABLE_PTHREAD 534 pthread_mutex_lock(&gai_mutex); 535 #endif 536 537 saved_h_errno = h_errno; 538 539 if (sa_in->sin_family != PF_INET) { 540 result = EAI_FAMILY; 541 goto end; 542 } else if (node == NULL && serv == NULL) { 543 result = EAI_NONAME; 544 goto end; 545 } 546 547 if (serv != NULL && servlen > 0) { 548 if (flags & NI_NUMERICSERV) 549 servent = NULL; 550 else if (flags & NI_DGRAM) 551 servent = getservbyport(sa_in->sin_port, "udp"); 552 else 553 servent = getservbyport(sa_in->sin_port, "tcp"); 554 555 if (servent != NULL) { 556 if (servlen <= strlen(servent->s_name)) { 557 result = EAI_OVERFLOW; 558 goto end; 559 } 560 strcpy(serv, servent->s_name); 561 } else { 562 if (servlen <= itoa_length(ntohs(sa_in->sin_port))) { 563 result = EAI_OVERFLOW; 564 goto end; 565 } 566 sprintf(serv, "%d", ntohs(sa_in->sin_port)); 567 } 568 } 569 570 if (node != NULL && nodelen > 0) { 571 if (flags & NI_NUMERICHOST) 572 hostent = NULL; 573 else { 574 hostent = gethostbyaddr((char *)&sa_in->sin_addr, 575 sizeof(struct in_addr), AF_INET); 576 } 577 if (hostent != NULL) { 578 if (nodelen <= strlen(hostent->h_name)) { 579 result = EAI_OVERFLOW; 580 goto end; 581 } 582 strcpy(node, hostent->h_name); 583 } else { 584 if (flags & NI_NAMEREQD) { 585 result = EAI_NONAME; 586 goto end; 587 } 588 ntoa_address = inet_ntoa(sa_in->sin_addr); 589 if (nodelen <= strlen(ntoa_address)) { 590 result = EAI_OVERFLOW; 591 goto end; 592 } 593 strcpy(node, ntoa_address); 594 } 595 596 } 597 598 end: 599 h_errno = saved_h_errno; 600 #ifdef ENABLE_PTHREAD 601 pthread_mutex_unlock(&gai_mutex); 602 #endif 603 return result; 604 } 605 606