getaddrinfo.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. /* Get address information (partial implementation).
  2. Copyright (C) 1997, 2001-2002, 2004-2012 Free Software Foundation, Inc.
  3. Contributed by Simon Josefsson <simon@josefsson.org>.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License
  13. along with this program; if not, write to the Free Software Foundation,
  14. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
  15. #include <config.h>
  16. /* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
  17. optimizes away the sa == NULL test below. */
  18. #define _GL_ARG_NONNULL(params)
  19. #include <netdb.h>
  20. #if HAVE_NETINET_IN_H
  21. # include <netinet/in.h>
  22. #endif
  23. /* Get inet_ntop. */
  24. #include <arpa/inet.h>
  25. /* Get calloc. */
  26. #include <stdlib.h>
  27. /* Get memcpy, strdup. */
  28. #include <string.h>
  29. /* Get snprintf. */
  30. #include <stdio.h>
  31. #include <stdbool.h>
  32. #include "gettext.h"
  33. #define _(String) gettext (String)
  34. #define N_(String) String
  35. /* BeOS has AF_INET, but not PF_INET. */
  36. #ifndef PF_INET
  37. # define PF_INET AF_INET
  38. #endif
  39. /* BeOS also lacks PF_UNSPEC. */
  40. #ifndef PF_UNSPEC
  41. # define PF_UNSPEC 0
  42. #endif
  43. #if defined _WIN32 || defined __WIN32__
  44. # define WINDOWS_NATIVE
  45. #endif
  46. /* gl_sockets_startup */
  47. #include "sockets.h"
  48. #ifdef WINDOWS_NATIVE
  49. typedef int (WSAAPI *getaddrinfo_func) (const char*, const char*,
  50. const struct addrinfo*,
  51. struct addrinfo**);
  52. typedef void (WSAAPI *freeaddrinfo_func) (struct addrinfo*);
  53. typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr*,
  54. socklen_t, char*, DWORD,
  55. char*, DWORD, int);
  56. static getaddrinfo_func getaddrinfo_ptr = NULL;
  57. static freeaddrinfo_func freeaddrinfo_ptr = NULL;
  58. static getnameinfo_func getnameinfo_ptr = NULL;
  59. static int
  60. use_win32_p (void)
  61. {
  62. static int done = 0;
  63. HMODULE h;
  64. if (done)
  65. return getaddrinfo_ptr ? 1 : 0;
  66. done = 1;
  67. h = GetModuleHandle ("ws2_32.dll");
  68. if (h)
  69. {
  70. getaddrinfo_ptr = (getaddrinfo_func) GetProcAddress (h, "getaddrinfo");
  71. freeaddrinfo_ptr = (freeaddrinfo_func) GetProcAddress (h, "freeaddrinfo");
  72. getnameinfo_ptr = (getnameinfo_func) GetProcAddress (h, "getnameinfo");
  73. }
  74. /* If either is missing, something is odd. */
  75. if (!getaddrinfo_ptr || !freeaddrinfo_ptr || !getnameinfo_ptr)
  76. {
  77. getaddrinfo_ptr = NULL;
  78. freeaddrinfo_ptr = NULL;
  79. getnameinfo_ptr = NULL;
  80. return 0;
  81. }
  82. gl_sockets_startup (SOCKETS_1_1);
  83. return 1;
  84. }
  85. #endif
  86. static inline bool
  87. validate_family (int family)
  88. {
  89. /* FIXME: Support more families. */
  90. #if HAVE_IPV4
  91. if (family == PF_INET)
  92. return true;
  93. #endif
  94. #if HAVE_IPV6
  95. if (family == PF_INET6)
  96. return true;
  97. #endif
  98. if (family == PF_UNSPEC)
  99. return true;
  100. return false;
  101. }
  102. /* Translate name of a service location and/or a service name to set of
  103. socket addresses. */
  104. int
  105. getaddrinfo (const char *restrict nodename,
  106. const char *restrict servname,
  107. const struct addrinfo *restrict hints,
  108. struct addrinfo **restrict res)
  109. {
  110. struct addrinfo *tmp;
  111. int port = 0;
  112. struct hostent *he;
  113. void *storage;
  114. size_t size;
  115. #if HAVE_IPV6
  116. struct v6_pair {
  117. struct addrinfo addrinfo;
  118. struct sockaddr_in6 sockaddr_in6;
  119. };
  120. #endif
  121. #if HAVE_IPV4
  122. struct v4_pair {
  123. struct addrinfo addrinfo;
  124. struct sockaddr_in sockaddr_in;
  125. };
  126. #endif
  127. #ifdef WINDOWS_NATIVE
  128. if (use_win32_p ())
  129. return getaddrinfo_ptr (nodename, servname, hints, res);
  130. #endif
  131. if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE)))
  132. /* FIXME: Support more flags. */
  133. return EAI_BADFLAGS;
  134. if (hints && !validate_family (hints->ai_family))
  135. return EAI_FAMILY;
  136. if (hints &&
  137. hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM)
  138. /* FIXME: Support other socktype. */
  139. return EAI_SOCKTYPE; /* FIXME: Better return code? */
  140. if (!nodename)
  141. {
  142. if (!(hints->ai_flags & AI_PASSIVE))
  143. return EAI_NONAME;
  144. #ifdef HAVE_IPV6
  145. nodename = (hints->ai_family == AF_INET6) ? "::" : "0.0.0.0";
  146. #else
  147. nodename = "0.0.0.0";
  148. #endif
  149. }
  150. if (servname)
  151. {
  152. struct servent *se = NULL;
  153. const char *proto =
  154. (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
  155. if (hints == NULL || !(hints->ai_flags & AI_NUMERICSERV))
  156. /* FIXME: Use getservbyname_r if available. */
  157. se = getservbyname (servname, proto);
  158. if (!se)
  159. {
  160. char *c;
  161. if (!(*servname >= '0' && *servname <= '9'))
  162. return EAI_NONAME;
  163. port = strtoul (servname, &c, 10);
  164. if (*c || port > 0xffff)
  165. return EAI_NONAME;
  166. port = htons (port);
  167. }
  168. else
  169. port = se->s_port;
  170. }
  171. /* FIXME: Use gethostbyname_r if available. */
  172. he = gethostbyname (nodename);
  173. if (!he || he->h_addr_list[0] == NULL)
  174. return EAI_NONAME;
  175. switch (he->h_addrtype)
  176. {
  177. #if HAVE_IPV6
  178. case PF_INET6:
  179. size = sizeof (struct v6_pair);
  180. break;
  181. #endif
  182. #if HAVE_IPV4
  183. case PF_INET:
  184. size = sizeof (struct v4_pair);
  185. break;
  186. #endif
  187. default:
  188. return EAI_NODATA;
  189. }
  190. storage = calloc (1, size);
  191. if (!storage)
  192. return EAI_MEMORY;
  193. switch (he->h_addrtype)
  194. {
  195. #if HAVE_IPV6
  196. case PF_INET6:
  197. {
  198. struct v6_pair *p = storage;
  199. struct sockaddr_in6 *sinp = &p->sockaddr_in6;
  200. tmp = &p->addrinfo;
  201. if (port)
  202. sinp->sin6_port = port;
  203. if (he->h_length != sizeof (sinp->sin6_addr))
  204. {
  205. free (storage);
  206. return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */
  207. }
  208. memcpy (&sinp->sin6_addr, he->h_addr_list[0], sizeof sinp->sin6_addr);
  209. tmp->ai_addr = (struct sockaddr *) sinp;
  210. tmp->ai_addrlen = sizeof *sinp;
  211. }
  212. break;
  213. #endif
  214. #if HAVE_IPV4
  215. case PF_INET:
  216. {
  217. struct v4_pair *p = storage;
  218. struct sockaddr_in *sinp = &p->sockaddr_in;
  219. tmp = &p->addrinfo;
  220. if (port)
  221. sinp->sin_port = port;
  222. if (he->h_length != sizeof (sinp->sin_addr))
  223. {
  224. free (storage);
  225. return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */
  226. }
  227. memcpy (&sinp->sin_addr, he->h_addr_list[0], sizeof sinp->sin_addr);
  228. tmp->ai_addr = (struct sockaddr *) sinp;
  229. tmp->ai_addrlen = sizeof *sinp;
  230. }
  231. break;
  232. #endif
  233. default:
  234. free (storage);
  235. return EAI_NODATA;
  236. }
  237. if (hints && hints->ai_flags & AI_CANONNAME)
  238. {
  239. const char *cn;
  240. if (he->h_name)
  241. cn = he->h_name;
  242. else
  243. cn = nodename;
  244. tmp->ai_canonname = strdup (cn);
  245. if (!tmp->ai_canonname)
  246. {
  247. free (storage);
  248. return EAI_MEMORY;
  249. }
  250. }
  251. tmp->ai_protocol = (hints) ? hints->ai_protocol : 0;
  252. tmp->ai_socktype = (hints) ? hints->ai_socktype : 0;
  253. tmp->ai_addr->sa_family = he->h_addrtype;
  254. tmp->ai_family = he->h_addrtype;
  255. #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
  256. switch (he->h_addrtype)
  257. {
  258. #if HAVE_IPV4
  259. case AF_INET:
  260. tmp->ai_addr->sa_len = sizeof (struct sockaddr_in);
  261. break;
  262. #endif
  263. #if HAVE_IPV6
  264. case AF_INET6:
  265. tmp->ai_addr->sa_len = sizeof (struct sockaddr_in6);
  266. break;
  267. #endif
  268. }
  269. #endif
  270. /* FIXME: If more than one address, create linked list of addrinfo's. */
  271. *res = tmp;
  272. return 0;
  273. }
  274. /* Free 'addrinfo' structure AI including associated storage. */
  275. void
  276. freeaddrinfo (struct addrinfo *ai)
  277. {
  278. #ifdef WINDOWS_NATIVE
  279. if (use_win32_p ())
  280. {
  281. freeaddrinfo_ptr (ai);
  282. return;
  283. }
  284. #endif
  285. while (ai)
  286. {
  287. struct addrinfo *cur;
  288. cur = ai;
  289. ai = ai->ai_next;
  290. free (cur->ai_canonname);
  291. free (cur);
  292. }
  293. }
  294. int
  295. getnameinfo (const struct sockaddr *restrict sa, socklen_t salen,
  296. char *restrict node, socklen_t nodelen,
  297. char *restrict service, socklen_t servicelen,
  298. int flags)
  299. {
  300. #ifdef WINDOWS_NATIVE
  301. if (use_win32_p ())
  302. return getnameinfo_ptr (sa, salen, node, nodelen,
  303. service, servicelen, flags);
  304. #endif
  305. /* FIXME: Support other flags. */
  306. if ((node && nodelen > 0 && !(flags & NI_NUMERICHOST)) ||
  307. (service && servicelen > 0 && !(flags & NI_NUMERICHOST)) ||
  308. (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV)))
  309. return EAI_BADFLAGS;
  310. if (sa == NULL || salen < sizeof (sa->sa_family))
  311. return EAI_FAMILY;
  312. switch (sa->sa_family)
  313. {
  314. #if HAVE_IPV4
  315. case AF_INET:
  316. if (salen < sizeof (struct sockaddr_in))
  317. return EAI_FAMILY;
  318. break;
  319. #endif
  320. #if HAVE_IPV6
  321. case AF_INET6:
  322. if (salen < sizeof (struct sockaddr_in6))
  323. return EAI_FAMILY;
  324. break;
  325. #endif
  326. default:
  327. return EAI_FAMILY;
  328. }
  329. if (node && nodelen > 0 && flags & NI_NUMERICHOST)
  330. {
  331. switch (sa->sa_family)
  332. {
  333. #if HAVE_IPV4
  334. case AF_INET:
  335. if (!inet_ntop (AF_INET,
  336. &(((const struct sockaddr_in *) sa)->sin_addr),
  337. node, nodelen))
  338. return EAI_SYSTEM;
  339. break;
  340. #endif
  341. #if HAVE_IPV6
  342. case AF_INET6:
  343. if (!inet_ntop (AF_INET6,
  344. &(((const struct sockaddr_in6 *) sa)->sin6_addr),
  345. node, nodelen))
  346. return EAI_SYSTEM;
  347. break;
  348. #endif
  349. default:
  350. return EAI_FAMILY;
  351. }
  352. }
  353. if (service && servicelen > 0 && flags & NI_NUMERICSERV)
  354. switch (sa->sa_family)
  355. {
  356. #if HAVE_IPV4
  357. case AF_INET:
  358. #endif
  359. #if HAVE_IPV6
  360. case AF_INET6:
  361. #endif
  362. {
  363. unsigned short int port
  364. = ntohs (((const struct sockaddr_in *) sa)->sin_port);
  365. if (servicelen <= snprintf (service, servicelen, "%u", port))
  366. return EAI_OVERFLOW;
  367. }
  368. break;
  369. }
  370. return 0;
  371. }