getaddrinfo.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  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. * Default hints for getaddrinfo().
  173. */
  174. static struct addrinfo default_hints = {0, PF_UNSPEC, 0, 0,
  175. 0, NULL, NULL, NULL};
  176. /*
  177. * Mutex.
  178. */
  179. #ifdef ENABLE_PTHREAD
  180. static pthread_mutex_t gai_mutex = PTHREAD_MUTEX_INITIALIZER;
  181. #endif
  182. /*
  183. * Declaration of static functions.
  184. */
  185. #ifdef __STDC__
  186. static int is_integer(const char*);
  187. static int is_address(const char*);
  188. static int itoa_length(int);
  189. #else
  190. static int is_integer();
  191. static int is_address();
  192. static int itoa_length();
  193. #endif
  194. /*
  195. * gai_strerror().
  196. */
  197. const char* gai_strerror(ecode) int ecode;
  198. {
  199. if (ecode < 0 || ecode > EAI_SYSTEM)
  200. return _("Unknown error");
  201. return gettext(eai_errlist[ecode]);
  202. }
  203. /*
  204. * freeaddrinfo().
  205. */
  206. void freeaddrinfo(ai) struct addrinfo* ai;
  207. {
  208. struct addrinfo* next_ai;
  209. while (ai != NULL) {
  210. if (ai->ai_canonname != NULL)
  211. free(ai->ai_canonname);
  212. if (ai->ai_addr != NULL)
  213. free(ai->ai_addr);
  214. next_ai = ai->ai_next;
  215. free(ai);
  216. ai = next_ai;
  217. }
  218. }
  219. /*
  220. * Return 1 if the string `s' represents an integer.
  221. */
  222. static int is_integer(s) const char* s;
  223. {
  224. if (*s == '-' || *s == '+')
  225. s++;
  226. if (*s < '0' || '9' < *s)
  227. return 0;
  228. s++;
  229. while ('0' <= *s && *s <= '9')
  230. s++;
  231. return (*s == '\0');
  232. }
  233. /*
  234. * Return 1 if the string `s' represents an IPv4 address.
  235. * Unlike inet_addr(), it doesn't permit malformed nortation such
  236. * as "192.168".
  237. */
  238. static int is_address(s) const char* s;
  239. {
  240. const static char delimiters[] = {'.', '.', '.', '\0'};
  241. int i, j;
  242. int octet;
  243. for (i = 0; i < 4; i++) {
  244. if (*s == '0' && *(s + 1) != delimiters[i])
  245. return 0;
  246. for (j = 0, octet = 0; '0' <= *s && *s <= '9' && j < 3; s++, j++)
  247. octet = octet * 10 + (*s - '0');
  248. if (j == 0 || octet > 255 || *s != delimiters[i])
  249. return 0;
  250. s++;
  251. }
  252. return 1;
  253. }
  254. /*
  255. * Calcurate length of the string `s', where `s' is set by
  256. * sprintf(s, "%d", n).
  257. */
  258. static int itoa_length(n) int n;
  259. {
  260. int result = 1;
  261. if (n < 0) {
  262. n = -n;
  263. result++;
  264. }
  265. while (n >= 10) {
  266. result++;
  267. n /= 10;
  268. }
  269. return result;
  270. }
  271. /*
  272. * getaddrinfo().
  273. */
  274. int getaddrinfo(nodename, servname, hints, res) const char* nodename;
  275. const char* servname;
  276. const struct addrinfo* hints;
  277. struct addrinfo** res;
  278. {
  279. struct addrinfo* head_res = NULL;
  280. struct addrinfo* tail_res = NULL;
  281. struct addrinfo* new_res;
  282. struct sockaddr_in* sa_in;
  283. struct in_addr** addr_list;
  284. struct in_addr* addr_list_buf[2];
  285. struct in_addr addr_buf;
  286. struct in_addr** ap;
  287. struct servent* servent;
  288. struct hostent* hostent;
  289. const char* canonname = NULL;
  290. in_port_t port;
  291. int saved_h_errno;
  292. int result = 0;
  293. #ifdef ENABLE_PTHREAD
  294. pthread_mutex_lock(&gai_mutex);
  295. #endif
  296. saved_h_errno = h_errno;
  297. if (nodename == NULL && servname == NULL) {
  298. result = EAI_NONAME;
  299. goto end;
  300. }
  301. if (hints != NULL) {
  302. if (hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC) {
  303. result = EAI_FAMILY;
  304. goto end;
  305. }
  306. if (hints->ai_socktype != SOCK_DGRAM && hints->ai_socktype != SOCK_STREAM &&
  307. hints->ai_socktype != 0) {
  308. result = EAI_SOCKTYPE;
  309. goto end;
  310. }
  311. }
  312. else {
  313. hints = &default_hints;
  314. }
  315. if (servname != NULL) {
  316. if (is_integer(servname))
  317. port = htons(atoi(servname));
  318. else {
  319. if (hints->ai_flags & AI_NUMERICSERV) {
  320. result = EAI_NONAME;
  321. goto end;
  322. }
  323. if (hints->ai_socktype == SOCK_DGRAM)
  324. servent = getservbyname(servname, "udp");
  325. else if (hints->ai_socktype == SOCK_STREAM)
  326. servent = getservbyname(servname, "tcp");
  327. else if (hints->ai_socktype == 0)
  328. servent = getservbyname(servname, "tcp");
  329. else {
  330. result = EAI_SOCKTYPE;
  331. goto end;
  332. }
  333. if (servent == NULL) {
  334. result = EAI_SERVICE;
  335. goto end;
  336. }
  337. port = servent->s_port;
  338. }
  339. }
  340. else {
  341. port = htons(0);
  342. }
  343. if (nodename != NULL) {
  344. if (is_address(nodename)) {
  345. addr_buf.s_addr = inet_addr(nodename);
  346. addr_list_buf[0] = &addr_buf;
  347. addr_list_buf[1] = NULL;
  348. addr_list = addr_list_buf;
  349. if (hints->ai_flags & AI_CANONNAME &&
  350. !(hints->ai_flags & AI_NUMERICHOST)) {
  351. hostent =
  352. gethostbyaddr((char*)&addr_buf, sizeof(struct in_addr), AF_INET);
  353. if (hostent != NULL)
  354. canonname = hostent->h_name;
  355. else
  356. canonname = nodename;
  357. }
  358. }
  359. else {
  360. if (hints->ai_flags & AI_NUMERICHOST) {
  361. result = EAI_NONAME;
  362. goto end;
  363. }
  364. hostent = gethostbyname(nodename);
  365. if (hostent == NULL) {
  366. switch (h_errno) {
  367. case HOST_NOT_FOUND:
  368. case NO_DATA:
  369. result = EAI_NONAME;
  370. goto end;
  371. case TRY_AGAIN:
  372. result = EAI_AGAIN;
  373. goto end;
  374. default:
  375. result = EAI_FAIL;
  376. goto end;
  377. }
  378. }
  379. addr_list = (struct in_addr**)hostent->h_addr_list;
  380. if (hints->ai_flags & AI_CANONNAME)
  381. canonname = hostent->h_name;
  382. }
  383. }
  384. else {
  385. if (hints->ai_flags & AI_PASSIVE)
  386. addr_buf.s_addr = htonl(INADDR_ANY);
  387. else
  388. addr_buf.s_addr = htonl(0x7F000001);
  389. addr_list_buf[0] = &addr_buf;
  390. addr_list_buf[1] = NULL;
  391. addr_list = addr_list_buf;
  392. }
  393. for (ap = addr_list; *ap != NULL; ap++) {
  394. new_res = (struct addrinfo*)malloc(sizeof(struct addrinfo));
  395. if (new_res == NULL) {
  396. if (head_res != NULL)
  397. freeaddrinfo(head_res);
  398. result = EAI_MEMORY;
  399. goto end;
  400. }
  401. new_res->ai_family = PF_INET;
  402. new_res->ai_socktype = hints->ai_socktype;
  403. new_res->ai_protocol = hints->ai_protocol;
  404. new_res->ai_addr = NULL;
  405. new_res->ai_addrlen = sizeof(struct sockaddr_in);
  406. new_res->ai_canonname = NULL;
  407. new_res->ai_next = NULL;
  408. new_res->ai_addr = (struct sockaddr*)malloc(sizeof(struct sockaddr_in));
  409. if (new_res->ai_addr == NULL) {
  410. free(new_res);
  411. if (head_res != NULL)
  412. freeaddrinfo(head_res);
  413. result = EAI_MEMORY;
  414. goto end;
  415. }
  416. sa_in = (struct sockaddr_in*)new_res->ai_addr;
  417. memset(sa_in, 0, sizeof(struct sockaddr_in));
  418. sa_in->sin_family = PF_INET;
  419. sa_in->sin_port = port;
  420. memcpy(&sa_in->sin_addr, *ap, sizeof(struct in_addr));
  421. if (head_res == NULL)
  422. head_res = new_res;
  423. else
  424. tail_res->ai_next = new_res;
  425. tail_res = new_res;
  426. }
  427. if (canonname != NULL && head_res != NULL) {
  428. head_res->ai_canonname = (char*)malloc(strlen(canonname) + 1);
  429. if (head_res->ai_canonname != NULL)
  430. strcpy(head_res->ai_canonname, canonname);
  431. }
  432. *res = head_res;
  433. end:
  434. h_errno = saved_h_errno;
  435. #ifdef ENABLE_PTHREAD
  436. pthread_mutex_unlock(&gai_mutex);
  437. #endif
  438. return result;
  439. }
  440. /*
  441. * getnameinfo().
  442. */
  443. int getnameinfo(sa, salen, node, nodelen, serv, servlen, flags) const
  444. struct sockaddr* sa;
  445. socklen_t salen;
  446. char* node;
  447. socklen_t nodelen;
  448. char* serv;
  449. socklen_t servlen;
  450. int flags;
  451. {
  452. const struct sockaddr_in* sa_in = (const struct sockaddr_in*)sa;
  453. struct hostent* hostent;
  454. struct servent* servent;
  455. char* ntoa_address;
  456. int saved_h_errno;
  457. int result = 0;
  458. #ifdef ENABLE_PTHREAD
  459. pthread_mutex_lock(&gai_mutex);
  460. #endif
  461. saved_h_errno = h_errno;
  462. if (sa_in->sin_family != PF_INET) {
  463. result = EAI_FAMILY;
  464. goto end;
  465. }
  466. else if (node == NULL && serv == NULL) {
  467. result = EAI_NONAME;
  468. goto end;
  469. }
  470. if (serv != NULL && servlen > 0) {
  471. if (flags & NI_NUMERICSERV)
  472. servent = NULL;
  473. else if (flags & NI_DGRAM)
  474. servent = getservbyport(sa_in->sin_port, "udp");
  475. else
  476. servent = getservbyport(sa_in->sin_port, "tcp");
  477. if (servent != NULL) {
  478. if (servlen <= strlen(servent->s_name)) {
  479. result = EAI_OVERFLOW;
  480. goto end;
  481. }
  482. strcpy(serv, servent->s_name);
  483. }
  484. else {
  485. if (servlen <= itoa_length(ntohs(sa_in->sin_port))) {
  486. result = EAI_OVERFLOW;
  487. goto end;
  488. }
  489. sprintf(serv, "%d", ntohs(sa_in->sin_port));
  490. }
  491. }
  492. if (node != NULL && nodelen > 0) {
  493. if (flags & NI_NUMERICHOST)
  494. hostent = NULL;
  495. else {
  496. hostent = gethostbyaddr((char*)&sa_in->sin_addr, sizeof(struct in_addr),
  497. AF_INET);
  498. }
  499. if (hostent != NULL) {
  500. if (nodelen <= strlen(hostent->h_name)) {
  501. result = EAI_OVERFLOW;
  502. goto end;
  503. }
  504. strcpy(node, hostent->h_name);
  505. }
  506. else {
  507. if (flags & NI_NAMEREQD) {
  508. result = EAI_NONAME;
  509. goto end;
  510. }
  511. ntoa_address = inet_ntoa(sa_in->sin_addr);
  512. if (nodelen <= strlen(ntoa_address)) {
  513. result = EAI_OVERFLOW;
  514. goto end;
  515. }
  516. strcpy(node, ntoa_address);
  517. }
  518. }
  519. end:
  520. h_errno = saved_h_errno;
  521. #ifdef ENABLE_PTHREAD
  522. pthread_mutex_unlock(&gai_mutex);
  523. #endif
  524. return result;
  525. }