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 *
gai_strerror(ecode)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
freeaddrinfo(ai)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
is_integer(s)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
is_address(s)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
itoa_length(n)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
getaddrinfo(nodename,servname,hints,res)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
getnameinfo(sa,salen,node,nodelen,serv,servlen,flags)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