getaddrinfo.c 10 KB

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