getaddrinfo.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. /*
  2. PostgreSQL Database Management System
  3. (formerly known as Postgres, then as Postgres95)
  4. Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
  5. Portions Copyright (c) 1994, The Regents of the University of California
  6. Permission to use, copy, modify, and distribute this software and its
  7. documentation for any purpose, without fee, and without a written agreement
  8. is hereby granted, provided that the above copyright notice and this paragraph
  9. and the following two paragraphs appear in all copies.
  10. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  11. DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
  12. LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
  13. EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
  14. SUCH DAMAGE.
  15. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  16. INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  17. AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
  18. ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
  19. TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  20. */
  21. /*-------------------------------------------------------------------------
  22. *
  23. * getaddrinfo.c
  24. * Support getaddrinfo() on platforms that don't have it.
  25. *
  26. * We also supply getnameinfo() here, assuming that the platform will have
  27. * it if and only if it has getaddrinfo(). If this proves false on some
  28. * platform, we'll need to split this file and provide a separate configure
  29. * test for getnameinfo().
  30. *
  31. * Copyright (c) 2003-2007, PostgreSQL Global Development Group
  32. *
  33. * Copyright (C) 2007 Jeremy Allison.
  34. * Modified to return multiple IPv4 addresses for Samba.
  35. *
  36. *-------------------------------------------------------------------------
  37. */
  38. #include "rsync.h"
  39. #ifndef SMB_MALLOC
  40. #define SMB_MALLOC(s) malloc(s)
  41. #endif
  42. #ifndef SMB_STRDUP
  43. #define SMB_STRDUP(s) strdup(s)
  44. #endif
  45. #ifndef HOST_NAME_MAX
  46. #define HOST_NAME_MAX 255
  47. #endif
  48. static int check_hostent_err(struct hostent *hp)
  49. {
  50. #ifndef INET6
  51. extern int h_errno;
  52. #endif
  53. if (!hp) {
  54. switch (h_errno) {
  55. case HOST_NOT_FOUND:
  56. case NO_DATA:
  57. return EAI_NONAME;
  58. case TRY_AGAIN:
  59. return EAI_AGAIN;
  60. case NO_RECOVERY:
  61. default:
  62. return EAI_FAIL;
  63. }
  64. }
  65. if (!hp->h_name || hp->h_addrtype != AF_INET) {
  66. return EAI_FAIL;
  67. }
  68. return 0;
  69. }
  70. static char *canon_name_from_hostent(struct hostent *hp,
  71. int *perr)
  72. {
  73. char *ret = NULL;
  74. *perr = check_hostent_err(hp);
  75. if (*perr) {
  76. return NULL;
  77. }
  78. ret = SMB_STRDUP(hp->h_name);
  79. if (!ret) {
  80. *perr = EAI_MEMORY;
  81. }
  82. return ret;
  83. }
  84. static char *get_my_canon_name(int *perr)
  85. {
  86. char name[HOST_NAME_MAX+1];
  87. if (gethostname(name, HOST_NAME_MAX) == -1) {
  88. *perr = EAI_FAIL;
  89. return NULL;
  90. }
  91. /* Ensure null termination. */
  92. name[HOST_NAME_MAX] = '\0';
  93. return canon_name_from_hostent(gethostbyname(name), perr);
  94. }
  95. static char *get_canon_name_from_addr(struct in_addr ip,
  96. int *perr)
  97. {
  98. return canon_name_from_hostent(
  99. gethostbyaddr((void *)&ip, sizeof ip, AF_INET),
  100. perr);
  101. }
  102. static struct addrinfo *alloc_entry(const struct addrinfo *hints,
  103. struct in_addr ip,
  104. unsigned short port)
  105. {
  106. struct sockaddr_in *psin = NULL;
  107. struct addrinfo *ai = SMB_MALLOC(sizeof(*ai));
  108. if (!ai) {
  109. return NULL;
  110. }
  111. memset(ai, '\0', sizeof(*ai));
  112. psin = SMB_MALLOC(sizeof(*psin));
  113. if (!psin) {
  114. free(ai);
  115. return NULL;
  116. }
  117. memset(psin, '\0', sizeof(*psin));
  118. psin->sin_family = AF_INET;
  119. psin->sin_port = htons(port);
  120. psin->sin_addr = ip;
  121. ai->ai_flags = 0;
  122. ai->ai_family = AF_INET;
  123. ai->ai_socktype = hints->ai_socktype;
  124. ai->ai_protocol = hints->ai_protocol;
  125. ai->ai_addrlen = sizeof(*psin);
  126. ai->ai_addr = (struct sockaddr *) psin;
  127. ai->ai_canonname = NULL;
  128. ai->ai_next = NULL;
  129. return ai;
  130. }
  131. /*
  132. * get address info for a single ipv4 address.
  133. *
  134. * Bugs: - servname can only be a number, not text.
  135. */
  136. static int getaddr_info_single_addr(const char *service,
  137. uint32 addr,
  138. const struct addrinfo *hints,
  139. struct addrinfo **res)
  140. {
  141. struct addrinfo *ai = NULL;
  142. struct in_addr ip;
  143. unsigned short port = 0;
  144. if (service) {
  145. port = (unsigned short)atoi(service);
  146. }
  147. ip.s_addr = htonl(addr);
  148. ai = alloc_entry(hints, ip, port);
  149. if (!ai) {
  150. return EAI_MEMORY;
  151. }
  152. /* If we're asked for the canonical name,
  153. * make sure it returns correctly. */
  154. if (!(hints->ai_flags & AI_NUMERICSERV) &&
  155. hints->ai_flags & AI_CANONNAME) {
  156. int err;
  157. if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) {
  158. ai->ai_canonname = get_my_canon_name(&err);
  159. } else {
  160. ai->ai_canonname =
  161. get_canon_name_from_addr(ip,&err);
  162. }
  163. if (ai->ai_canonname == NULL) {
  164. freeaddrinfo(ai);
  165. return err;
  166. }
  167. }
  168. *res = ai;
  169. return 0;
  170. }
  171. /*
  172. * get address info for multiple ipv4 addresses.
  173. *
  174. * Bugs: - servname can only be a number, not text.
  175. */
  176. static int getaddr_info_name(const char *node,
  177. const char *service,
  178. const struct addrinfo *hints,
  179. struct addrinfo **res)
  180. {
  181. struct addrinfo *listp = NULL, *prevp = NULL;
  182. char **pptr = NULL;
  183. int err;
  184. struct hostent *hp = NULL;
  185. unsigned short port = 0;
  186. if (service) {
  187. port = (unsigned short)atoi(service);
  188. }
  189. hp = gethostbyname(node);
  190. err = check_hostent_err(hp);
  191. if (err) {
  192. return err;
  193. }
  194. for(pptr = hp->h_addr_list; *pptr; pptr++) {
  195. struct in_addr ip = *(struct in_addr *)*pptr;
  196. struct addrinfo *ai = alloc_entry(hints, ip, port);
  197. if (!ai) {
  198. freeaddrinfo(listp);
  199. return EAI_MEMORY;
  200. }
  201. if (!listp) {
  202. listp = ai;
  203. prevp = ai;
  204. ai->ai_canonname = SMB_STRDUP(hp->h_name);
  205. if (!ai->ai_canonname) {
  206. freeaddrinfo(listp);
  207. return EAI_MEMORY;
  208. }
  209. } else {
  210. prevp->ai_next = ai;
  211. prevp = ai;
  212. }
  213. }
  214. *res = listp;
  215. return 0;
  216. }
  217. /*
  218. * get address info for ipv4 sockets.
  219. *
  220. * Bugs: - servname can only be a number, not text.
  221. */
  222. int getaddrinfo(const char *node,
  223. const char *service,
  224. const struct addrinfo * hintp,
  225. struct addrinfo ** res)
  226. {
  227. struct addrinfo hints;
  228. /* Setup the hints struct. */
  229. if (hintp == NULL) {
  230. memset(&hints, 0, sizeof(hints));
  231. hints.ai_family = AF_INET;
  232. hints.ai_socktype = SOCK_STREAM;
  233. } else {
  234. memcpy(&hints, hintp, sizeof(hints));
  235. }
  236. if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) {
  237. return EAI_FAMILY;
  238. }
  239. if (hints.ai_socktype == 0) {
  240. hints.ai_socktype = SOCK_STREAM;
  241. }
  242. if (!node && !service) {
  243. return EAI_NONAME;
  244. }
  245. if (node) {
  246. if (node[0] == '\0') {
  247. return getaddr_info_single_addr(service,
  248. INADDR_ANY,
  249. &hints,
  250. res);
  251. } else if (hints.ai_flags & AI_NUMERICHOST) {
  252. struct in_addr ip;
  253. if (inet_pton(AF_INET, node, &ip) <= 0)
  254. return EAI_FAIL;
  255. return getaddr_info_single_addr(service,
  256. ntohl(ip.s_addr),
  257. &hints,
  258. res);
  259. } else {
  260. return getaddr_info_name(node,
  261. service,
  262. &hints,
  263. res);
  264. }
  265. } else if (hints.ai_flags & AI_PASSIVE) {
  266. return getaddr_info_single_addr(service,
  267. INADDR_ANY,
  268. &hints,
  269. res);
  270. }
  271. return getaddr_info_single_addr(service,
  272. INADDR_LOOPBACK,
  273. &hints,
  274. res);
  275. }
  276. void freeaddrinfo(struct addrinfo *res)
  277. {
  278. struct addrinfo *next = NULL;
  279. for (;res; res = next) {
  280. next = res->ai_next;
  281. if (res->ai_canonname) {
  282. free(res->ai_canonname);
  283. }
  284. if (res->ai_addr) {
  285. free(res->ai_addr);
  286. }
  287. free(res);
  288. }
  289. }
  290. const char *gai_strerror(int errcode)
  291. {
  292. #ifdef HAVE_HSTRERROR
  293. int hcode;
  294. switch (errcode)
  295. {
  296. case EAI_NONAME:
  297. hcode = HOST_NOT_FOUND;
  298. break;
  299. case EAI_AGAIN:
  300. hcode = TRY_AGAIN;
  301. break;
  302. case EAI_FAIL:
  303. default:
  304. hcode = NO_RECOVERY;
  305. break;
  306. }
  307. return hstrerror(hcode);
  308. #else /* !HAVE_HSTRERROR */
  309. switch (errcode)
  310. {
  311. case EAI_NONAME:
  312. return "Unknown host";
  313. case EAI_AGAIN:
  314. return "Host name lookup failure";
  315. #ifdef EAI_BADFLAGS
  316. case EAI_BADFLAGS:
  317. return "Invalid argument";
  318. #endif
  319. #ifdef EAI_FAMILY
  320. case EAI_FAMILY:
  321. return "Address family not supported";
  322. #endif
  323. #ifdef EAI_MEMORY
  324. case EAI_MEMORY:
  325. return "Not enough memory";
  326. #endif
  327. #ifdef EAI_NODATA
  328. case EAI_NODATA:
  329. return "No host data of that type was found";
  330. #endif
  331. #ifdef EAI_SERVICE
  332. case EAI_SERVICE:
  333. return "Class type not found";
  334. #endif
  335. #ifdef EAI_SOCKTYPE
  336. case EAI_SOCKTYPE:
  337. return "Socket type not supported";
  338. #endif
  339. default:
  340. return "Unknown server error";
  341. }
  342. #endif /* HAVE_HSTRERROR */
  343. }
  344. static int gethostnameinfo(const struct sockaddr *sa,
  345. char *node,
  346. size_t nodelen,
  347. int flags)
  348. {
  349. int ret = -1;
  350. char *p = NULL;
  351. if (!(flags & NI_NUMERICHOST)) {
  352. struct hostent *hp = gethostbyaddr(
  353. (void *)&((struct sockaddr_in *)sa)->sin_addr,
  354. sizeof (struct in_addr),
  355. sa->sa_family);
  356. ret = check_hostent_err(hp);
  357. if (ret == 0) {
  358. /* Name looked up successfully. */
  359. ret = snprintf(node, nodelen, "%s", hp->h_name);
  360. if (ret < 0 || (size_t)ret >= nodelen) {
  361. return EAI_MEMORY;
  362. }
  363. if (flags & NI_NOFQDN) {
  364. p = strchr(node,'.');
  365. if (p) {
  366. *p = '\0';
  367. }
  368. }
  369. return 0;
  370. }
  371. if (flags & NI_NAMEREQD) {
  372. /* If we require a name and didn't get one,
  373. * automatically fail. */
  374. return ret;
  375. }
  376. /* Otherwise just fall into the numeric host code... */
  377. }
  378. p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
  379. ret = snprintf(node, nodelen, "%s", p);
  380. if (ret < 0 || (size_t)ret >= nodelen) {
  381. return EAI_MEMORY;
  382. }
  383. return 0;
  384. }
  385. static int getservicenameinfo(const struct sockaddr *sa,
  386. char *service,
  387. size_t servicelen,
  388. int flags)
  389. {
  390. int ret = -1;
  391. int port = ntohs(((struct sockaddr_in *)sa)->sin_port);
  392. if (!(flags & NI_NUMERICSERV)) {
  393. struct servent *se = getservbyport(
  394. port,
  395. (flags & NI_DGRAM) ? "udp" : "tcp");
  396. if (se && se->s_name) {
  397. /* Service name looked up successfully. */
  398. ret = snprintf(service, servicelen, "%s", se->s_name);
  399. if (ret < 0 || (size_t)ret >= servicelen) {
  400. return EAI_MEMORY;
  401. }
  402. return 0;
  403. }
  404. /* Otherwise just fall into the numeric service code... */
  405. }
  406. ret = snprintf(service, servicelen, "%d", port);
  407. if (ret < 0 || (size_t)ret >= servicelen) {
  408. return EAI_MEMORY;
  409. }
  410. return 0;
  411. }
  412. /*
  413. * Convert an ipv4 address to a hostname.
  414. *
  415. * Bugs: - No IPv6 support.
  416. */
  417. int getnameinfo(const struct sockaddr *sa, socklen_t salen,
  418. char *node, size_t nodelen,
  419. char *service, size_t servicelen, int flags)
  420. {
  421. /* Invalid arguments. */
  422. if (sa == NULL || (node == NULL && service == NULL)) {
  423. return EAI_FAIL;
  424. }
  425. if (sa->sa_family != AF_INET) {
  426. return EAI_FAIL;
  427. }
  428. if (salen < (socklen_t)sizeof (struct sockaddr_in)) {
  429. return EAI_FAIL;
  430. }
  431. if (node) {
  432. int ret = gethostnameinfo(sa, node, nodelen, flags);
  433. if (ret)
  434. return ret;
  435. }
  436. if (service) {
  437. return getservicenameinfo(sa, service, servicelen, flags);
  438. }
  439. return 0;
  440. }