/crypto/heimdal/lib/roken/getaddrinfo.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 414 lines · 318 code · 48 blank · 48 comment · 117 complexity · 57f368935138c4719e2207ab8902e594 MD5 · raw file

  1. /*
  2. * Copyright (c) 1999 - 2001 Kungliga Tekniska Hรถgskolan
  3. * (Royal Institute of Technology, Stockholm, Sweden).
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. *
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * 3. Neither the name of the Institute nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #include <config.h>
  34. #include "roken.h"
  35. /*
  36. * uses hints->ai_socktype and hints->ai_protocol
  37. */
  38. static int
  39. get_port_protocol_socktype (const char *servname,
  40. const struct addrinfo *hints,
  41. int *port,
  42. int *protocol,
  43. int *socktype)
  44. {
  45. struct servent *se;
  46. const char *proto_str = NULL;
  47. *socktype = 0;
  48. if (hints != NULL && hints->ai_protocol != 0) {
  49. struct protoent *protoent = getprotobynumber (hints->ai_protocol);
  50. if (protoent == NULL)
  51. return EAI_SOCKTYPE; /* XXX */
  52. proto_str = protoent->p_name;
  53. *protocol = protoent->p_proto;
  54. }
  55. if (hints != NULL)
  56. *socktype = hints->ai_socktype;
  57. if (*socktype == SOCK_STREAM) {
  58. se = getservbyname (servname, proto_str ? proto_str : "tcp");
  59. if (proto_str == NULL)
  60. *protocol = IPPROTO_TCP;
  61. } else if (*socktype == SOCK_DGRAM) {
  62. se = getservbyname (servname, proto_str ? proto_str : "udp");
  63. if (proto_str == NULL)
  64. *protocol = IPPROTO_UDP;
  65. } else if (*socktype == 0) {
  66. if (proto_str != NULL) {
  67. se = getservbyname (servname, proto_str);
  68. } else {
  69. se = getservbyname (servname, "tcp");
  70. *protocol = IPPROTO_TCP;
  71. *socktype = SOCK_STREAM;
  72. if (se == NULL) {
  73. se = getservbyname (servname, "udp");
  74. *protocol = IPPROTO_UDP;
  75. *socktype = SOCK_DGRAM;
  76. }
  77. }
  78. } else
  79. return EAI_SOCKTYPE;
  80. if (se == NULL) {
  81. char *endstr;
  82. *port = htons(strtol (servname, &endstr, 10));
  83. if (servname == endstr)
  84. return EAI_NONAME;
  85. } else {
  86. *port = se->s_port;
  87. }
  88. return 0;
  89. }
  90. static int
  91. add_one (int port, int protocol, int socktype,
  92. struct addrinfo ***ptr,
  93. int (*func)(struct addrinfo *, void *data, int port),
  94. void *data,
  95. char *canonname)
  96. {
  97. struct addrinfo *a;
  98. int ret;
  99. a = malloc (sizeof (*a));
  100. if (a == NULL)
  101. return EAI_MEMORY;
  102. memset (a, 0, sizeof(*a));
  103. a->ai_flags = 0;
  104. a->ai_next = NULL;
  105. a->ai_protocol = protocol;
  106. a->ai_socktype = socktype;
  107. a->ai_canonname = canonname;
  108. ret = (*func)(a, data, port);
  109. if (ret) {
  110. free (a);
  111. return ret;
  112. }
  113. **ptr = a;
  114. *ptr = &a->ai_next;
  115. return 0;
  116. }
  117. static int
  118. const_v4 (struct addrinfo *a, void *data, int port)
  119. {
  120. struct sockaddr_in *sin4;
  121. struct in_addr *addr = (struct in_addr *)data;
  122. a->ai_family = PF_INET;
  123. a->ai_addrlen = sizeof(*sin4);
  124. a->ai_addr = malloc (sizeof(*sin4));
  125. if (a->ai_addr == NULL)
  126. return EAI_MEMORY;
  127. sin4 = (struct sockaddr_in *)a->ai_addr;
  128. memset (sin4, 0, sizeof(*sin4));
  129. sin4->sin_family = AF_INET;
  130. sin4->sin_port = port;
  131. sin4->sin_addr = *addr;
  132. return 0;
  133. }
  134. #ifdef HAVE_IPV6
  135. static int
  136. const_v6 (struct addrinfo *a, void *data, int port)
  137. {
  138. struct sockaddr_in6 *sin6;
  139. struct in6_addr *addr = (struct in6_addr *)data;
  140. a->ai_family = PF_INET6;
  141. a->ai_addrlen = sizeof(*sin6);
  142. a->ai_addr = malloc (sizeof(*sin6));
  143. if (a->ai_addr == NULL)
  144. return EAI_MEMORY;
  145. sin6 = (struct sockaddr_in6 *)a->ai_addr;
  146. memset (sin6, 0, sizeof(*sin6));
  147. sin6->sin6_family = AF_INET6;
  148. sin6->sin6_port = port;
  149. sin6->sin6_addr = *addr;
  150. return 0;
  151. }
  152. #endif
  153. /* this is mostly a hack for some versions of AIX that has a prototype
  154. for in6addr_loopback but no actual symbol in libc */
  155. #if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT)
  156. #define in6addr_loopback _roken_in6addr_loopback
  157. struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
  158. #endif
  159. static int
  160. get_null (const struct addrinfo *hints,
  161. int port, int protocol, int socktype,
  162. struct addrinfo **res)
  163. {
  164. struct in_addr v4_addr;
  165. #ifdef HAVE_IPV6
  166. struct in6_addr v6_addr;
  167. #endif
  168. struct addrinfo *first = NULL;
  169. struct addrinfo **current = &first;
  170. int family = PF_UNSPEC;
  171. int ret;
  172. if (hints != NULL)
  173. family = hints->ai_family;
  174. if (hints && hints->ai_flags & AI_PASSIVE) {
  175. v4_addr.s_addr = INADDR_ANY;
  176. #ifdef HAVE_IPV6
  177. v6_addr = in6addr_any;
  178. #endif
  179. } else {
  180. v4_addr.s_addr = htonl(INADDR_LOOPBACK);
  181. #ifdef HAVE_IPV6
  182. v6_addr = in6addr_loopback;
  183. #endif
  184. }
  185. #ifdef HAVE_IPV6
  186. if (family == PF_INET6 || family == PF_UNSPEC) {
  187. ret = add_one (port, protocol, socktype,
  188. &current, const_v6, &v6_addr, NULL);
  189. }
  190. #endif
  191. if (family == PF_INET || family == PF_UNSPEC) {
  192. ret = add_one (port, protocol, socktype,
  193. &current, const_v4, &v4_addr, NULL);
  194. }
  195. *res = first;
  196. return 0;
  197. }
  198. static int
  199. add_hostent (int port, int protocol, int socktype,
  200. struct addrinfo ***current,
  201. int (*func)(struct addrinfo *, void *data, int port),
  202. struct hostent *he, int *flags)
  203. {
  204. int ret;
  205. char *canonname = NULL;
  206. char **h;
  207. if (*flags & AI_CANONNAME) {
  208. struct hostent *he2 = NULL;
  209. const char *tmp_canon;
  210. tmp_canon = hostent_find_fqdn (he);
  211. if (strchr (tmp_canon, '.') == NULL) {
  212. int error;
  213. he2 = getipnodebyaddr (he->h_addr_list[0], he->h_length,
  214. he->h_addrtype, &error);
  215. if (he2 != NULL) {
  216. const char *tmp = hostent_find_fqdn (he2);
  217. if (strchr (tmp, '.') != NULL)
  218. tmp_canon = tmp;
  219. }
  220. }
  221. canonname = strdup (tmp_canon);
  222. if (he2 != NULL)
  223. freehostent (he2);
  224. if (canonname == NULL)
  225. return EAI_MEMORY;
  226. }
  227. for (h = he->h_addr_list; *h != NULL; ++h) {
  228. ret = add_one (port, protocol, socktype,
  229. current, func, *h, canonname);
  230. if (ret)
  231. return ret;
  232. if (*flags & AI_CANONNAME) {
  233. *flags &= ~AI_CANONNAME;
  234. canonname = NULL;
  235. }
  236. }
  237. return 0;
  238. }
  239. static int
  240. get_number (const char *nodename,
  241. const struct addrinfo *hints,
  242. int port, int protocol, int socktype,
  243. struct addrinfo **res)
  244. {
  245. struct addrinfo *first = NULL;
  246. struct addrinfo **current = &first;
  247. int family = PF_UNSPEC;
  248. int ret;
  249. if (hints != NULL) {
  250. family = hints->ai_family;
  251. }
  252. #ifdef HAVE_IPV6
  253. if (family == PF_INET6 || family == PF_UNSPEC) {
  254. struct in6_addr v6_addr;
  255. if (inet_pton (PF_INET6, nodename, &v6_addr) == 1) {
  256. ret = add_one (port, protocol, socktype,
  257. &current, const_v6, &v6_addr, NULL);
  258. *res = first;
  259. return ret;
  260. }
  261. }
  262. #endif
  263. if (family == PF_INET || family == PF_UNSPEC) {
  264. struct in_addr v4_addr;
  265. if (inet_pton (PF_INET, nodename, &v4_addr) == 1) {
  266. ret = add_one (port, protocol, socktype,
  267. &current, const_v4, &v4_addr, NULL);
  268. *res = first;
  269. return ret;
  270. }
  271. }
  272. return EAI_NONAME;
  273. }
  274. static int
  275. get_nodes (const char *nodename,
  276. const struct addrinfo *hints,
  277. int port, int protocol, int socktype,
  278. struct addrinfo **res)
  279. {
  280. struct addrinfo *first = NULL;
  281. struct addrinfo **current = &first;
  282. int family = PF_UNSPEC;
  283. int flags = 0;
  284. int ret = EAI_NONAME;
  285. int error;
  286. if (hints != NULL) {
  287. family = hints->ai_family;
  288. flags = hints->ai_flags;
  289. }
  290. #ifdef HAVE_IPV6
  291. if (family == PF_INET6 || family == PF_UNSPEC) {
  292. struct hostent *he;
  293. he = getipnodebyname (nodename, PF_INET6, 0, &error);
  294. if (he != NULL) {
  295. ret = add_hostent (port, protocol, socktype,
  296. &current, const_v6, he, &flags);
  297. freehostent (he);
  298. }
  299. }
  300. #endif
  301. if (family == PF_INET || family == PF_UNSPEC) {
  302. struct hostent *he;
  303. he = getipnodebyname (nodename, PF_INET, 0, &error);
  304. if (he != NULL) {
  305. ret = add_hostent (port, protocol, socktype,
  306. &current, const_v4, he, &flags);
  307. freehostent (he);
  308. }
  309. }
  310. *res = first;
  311. return ret;
  312. }
  313. /*
  314. * hints:
  315. *
  316. * struct addrinfo {
  317. * int ai_flags;
  318. * int ai_family;
  319. * int ai_socktype;
  320. * int ai_protocol;
  321. * ...
  322. * };
  323. */
  324. ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
  325. getaddrinfo(const char *nodename,
  326. const char *servname,
  327. const struct addrinfo *hints,
  328. struct addrinfo **res)
  329. {
  330. int ret;
  331. int port = 0;
  332. int protocol = 0;
  333. int socktype = 0;
  334. *res = NULL;
  335. if (servname == NULL && nodename == NULL)
  336. return EAI_NONAME;
  337. if (hints != NULL
  338. && hints->ai_family != PF_UNSPEC
  339. && hints->ai_family != PF_INET
  340. #ifdef HAVE_IPV6
  341. && hints->ai_family != PF_INET6
  342. #endif
  343. )
  344. return EAI_FAMILY;
  345. if (servname != NULL) {
  346. ret = get_port_protocol_socktype (servname, hints,
  347. &port, &protocol, &socktype);
  348. if (ret)
  349. return ret;
  350. }
  351. if (nodename != NULL) {
  352. ret = get_number (nodename, hints, port, protocol, socktype, res);
  353. if (ret) {
  354. if(hints && hints->ai_flags & AI_NUMERICHOST)
  355. ret = EAI_NONAME;
  356. else
  357. ret = get_nodes (nodename, hints, port, protocol, socktype,
  358. res);
  359. }
  360. } else {
  361. ret = get_null (hints, port, protocol, socktype, res);
  362. }
  363. if (ret)
  364. freeaddrinfo (*res);
  365. return ret;
  366. }