getaddrinfo.c 14 KB

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