getaddrinfo.c 11 KB

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