Home | History | Annotate | Download | only in missing
      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