getaddrinfo.c 11 KB

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