hostip.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. /*****************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 2001, Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * In order to be useful for every potential user, curl and libcurl are
  11. * dual-licensed under the MPL and the MIT/X-derivate licenses.
  12. *
  13. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  14. * copies of the Software, and permit persons to whom the Software is
  15. * furnished to do so, under the terms of the MPL or the MIT/X-derivate
  16. * licenses. You may pick one of these licenses.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * $Id$
  22. *****************************************************************************/
  23. #include "setup.h"
  24. #include <string.h>
  25. #include <errno.h>
  26. #define _REENTRANT
  27. #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
  28. #include <winsock.h>
  29. #else
  30. #ifdef HAVE_SYS_TYPES_H
  31. #include <sys/types.h>
  32. #endif
  33. #ifdef HAVE_SYS_SOCKET_H
  34. #include <sys/socket.h>
  35. #endif
  36. #ifdef HAVE_NETINET_IN_H
  37. #include <netinet/in.h>
  38. #endif
  39. #ifdef HAVE_NETDB_H
  40. #include <netdb.h>
  41. #endif
  42. #ifdef HAVE_ARPA_INET_H
  43. #include <arpa/inet.h>
  44. #endif
  45. #ifdef HAVE_STDLIB_H
  46. #include <stdlib.h> /* required for free() prototypes */
  47. #endif
  48. #ifdef VMS
  49. #include <in.h>
  50. #include <inet.h>
  51. #include <stdlib.h>
  52. #endif
  53. #endif
  54. #include "urldata.h"
  55. #include "sendf.h"
  56. #include "hostip.h"
  57. #include "hash.h"
  58. #define _MPRINTF_REPLACE /* use our functions only */
  59. #include <curl/mprintf.h>
  60. #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
  61. #include "inet_ntoa_r.h"
  62. #endif
  63. /* The last #include file should be: */
  64. #ifdef MALLOCDEBUG
  65. #include "memdebug.h"
  66. #endif
  67. static curl_hash hostname_cache;
  68. static int host_cache_initialized;
  69. void Curl_global_host_cache_init(void)
  70. {
  71. if (!host_cache_initialized) {
  72. curl_hash_init(&hostname_cache, 7, Curl_freeaddrinfo);
  73. host_cache_initialized = 1;
  74. }
  75. }
  76. curl_hash *Curl_global_host_cache_get(void)
  77. {
  78. return &hostname_cache;
  79. }
  80. void Curl_global_host_cache_dtor(void)
  81. {
  82. if (host_cache_initialized) {
  83. curl_hash_clean(&hostname_cache);
  84. host_cache_initialized = 0;
  85. }
  86. }
  87. struct curl_dns_cache_entry {
  88. Curl_addrinfo *addr;
  89. time_t timestamp;
  90. };
  91. /* count the number of characters that an integer takes up */
  92. static int _num_chars(int i)
  93. {
  94. int chars = 0;
  95. /* While the number divided by 10 is greater than one,
  96. * re-divide the number by 10, and increment the number of
  97. * characters by 1.
  98. *
  99. * this relies on the fact that for every multiple of 10,
  100. * a new digit is added onto every number
  101. */
  102. do {
  103. chars++;
  104. i = (int) i / 10;
  105. } while (i >= 1);
  106. return chars;
  107. }
  108. /* Create a hostcache id */
  109. static char *
  110. _create_hostcache_id(char *server, int port, ssize_t *entry_len)
  111. {
  112. char *id = NULL;
  113. /* Get the length of the new entry id */
  114. *entry_len = *entry_len + /* Hostname length */
  115. 1 + /* The ':' seperator */
  116. _num_chars(port); /* The number of characters the port will take up */
  117. /* Allocate the new entry id */
  118. id = malloc(*entry_len + 1);
  119. if (!id) {
  120. return NULL;
  121. }
  122. /* Create the new entry */
  123. /* If sprintf() doesn't return the entry length, that signals failure */
  124. if (sprintf(id, "%s:%d", server, port) != *entry_len) {
  125. /* Free the allocated id, set length to zero and return NULL */
  126. *entry_len = 0;
  127. free(id);
  128. return NULL;
  129. }
  130. return id;
  131. }
  132. /* Macro to save redundant free'ing of entry_id */
  133. #define _hostcache_return(__v) \
  134. { \
  135. free(entry_id); \
  136. return (__v); \
  137. }
  138. Curl_addrinfo *Curl_resolv(struct SessionHandle *data,
  139. char *hostname,
  140. int port,
  141. char **bufp)
  142. {
  143. char *entry_id = NULL;
  144. struct curl_dns_cache_entry *p = NULL;
  145. ssize_t entry_len;
  146. time_t now;
  147. /* If the host cache timeout is 0, we don't do DNS cach'ing
  148. so fall through */
  149. if (data->set.dns_cache_timeout == 0) {
  150. return Curl_getaddrinfo(data, hostname, port, bufp);
  151. }
  152. /* Create an entry id, based upon the hostname and port */
  153. entry_len = strlen(hostname);
  154. entry_id = _create_hostcache_id(hostname, port, &entry_len);
  155. /* If we can't create the entry id, don't cache, just fall-through
  156. to the plain Curl_getaddrinfo() */
  157. if (!entry_id) {
  158. return Curl_getaddrinfo(data, hostname, port, bufp);
  159. }
  160. time(&now);
  161. /* See if its already in our dns cache */
  162. if (entry_id && curl_hash_find(data->hostcache, entry_id, entry_len+1, (void **) &p)) {
  163. /* Do we need to check for a cache timeout? */
  164. if (data->set.dns_cache_timeout != -1) {
  165. /* Return if the entry has not timed out */
  166. if ((now - p->timestamp) < data->set.dns_cache_timeout) {
  167. _hostcache_return(p->addr);
  168. }
  169. }
  170. else {
  171. _hostcache_return(p->addr);
  172. }
  173. }
  174. /* Create a new cache entry */
  175. p = (struct curl_dns_cache_entry *) malloc(sizeof(struct curl_dns_cache_entry));
  176. if (!p) {
  177. _hostcache_return(NULL);
  178. }
  179. p->addr = Curl_getaddrinfo(data, hostname, port, bufp);
  180. if (!p->addr) {
  181. free(p);
  182. _hostcache_return(NULL);
  183. }
  184. p->timestamp = now;
  185. /* Save it in our host cache */
  186. curl_hash_update(data->hostcache, entry_id, entry_len+1, (const void *) p);
  187. _hostcache_return(p->addr);
  188. }
  189. /*
  190. * This is a wrapper function for freeing name information in a protocol
  191. * independent way. This takes care of using the appropriate underlaying
  192. * proper function.
  193. */
  194. void Curl_freeaddrinfo(void *freethis)
  195. {
  196. struct curl_dns_cache_entry *p = (struct curl_dns_cache_entry *) freethis;
  197. #ifdef ENABLE_IPV6
  198. freeaddrinfo(p->addr);
  199. #else
  200. free(p->addr);
  201. #endif
  202. free(p);
  203. }
  204. /* --- resolve name or IP-number --- */
  205. #ifdef ENABLE_IPV6
  206. #ifdef MALLOCDEBUG
  207. /* These two are strictly for memory tracing and are using the same
  208. * style as the family otherwise present in memdebug.c. I put these ones
  209. * here since they require a bunch of struct types I didn't wanna include
  210. * in memdebug.c
  211. */
  212. int curl_getaddrinfo(char *hostname, char *service,
  213. struct addrinfo *hints,
  214. struct addrinfo **result,
  215. int line, const char *source)
  216. {
  217. int res=(getaddrinfo)(hostname, service, hints, result);
  218. if(0 == res) {
  219. /* success */
  220. if(logfile)
  221. fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n",
  222. source, line, (void *)*result);
  223. }
  224. else {
  225. if(logfile)
  226. fprintf(logfile, "ADDR %s:%d getaddrinfo() failed\n",
  227. source, line);
  228. }
  229. return res;
  230. }
  231. void curl_freeaddrinfo(struct addrinfo *freethis,
  232. int line, const char *source)
  233. {
  234. (freeaddrinfo)(freethis);
  235. if(logfile)
  236. fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n",
  237. source, line, (void *)freethis);
  238. }
  239. #endif
  240. /*
  241. * Return name information about the given hostname and port number. If
  242. * successful, the 'addrinfo' is returned and the forth argument will point to
  243. * memory we need to free after use. That meory *MUST* be freed with
  244. * Curl_freeaddrinfo(), nothing else.
  245. */
  246. Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
  247. char *hostname,
  248. int port,
  249. char **bufp)
  250. {
  251. struct addrinfo hints, *res;
  252. int error;
  253. char sbuf[NI_MAXSERV];
  254. memset(&hints, 0, sizeof(hints));
  255. hints.ai_family = PF_INET;
  256. hints.ai_socktype = SOCK_STREAM;
  257. hints.ai_flags = AI_CANONNAME;
  258. snprintf(sbuf, sizeof(sbuf), "%d", port);
  259. error = getaddrinfo(hostname, sbuf, &hints, &res);
  260. if (error) {
  261. infof(data, "getaddrinfo(3) failed for %s\n", hostname);
  262. return NULL;
  263. }
  264. *bufp=(char *)res; /* make it point to the result struct */
  265. return res;
  266. }
  267. #else /* following code is IPv4-only */
  268. #ifndef HAVE_GETHOSTBYNAME_R
  269. /**
  270. * Performs a "deep" copy of a hostent into a buffer (returns a pointer to the
  271. * copy). Make absolutely sure the destination buffer is big enough!
  272. *
  273. * Keith McGuigan
  274. * 10/3/2001 */
  275. static struct hostent* pack_hostent(char* buf, struct hostent* orig)
  276. {
  277. char* bufptr;
  278. struct hostent* copy;
  279. int i;
  280. char* str;
  281. int len;
  282. bufptr = buf;
  283. copy = (struct hostent*)bufptr;
  284. bufptr += sizeof(struct hostent);
  285. copy->h_name = bufptr;
  286. len = strlen(orig->h_name) + 1;
  287. strncpy(bufptr, orig->h_name, len);
  288. bufptr += len;
  289. /* we align on even 64bit boundaries for safety */
  290. #define MEMALIGN(x) (((unsigned long)(x)&0xfffffff8)+8)
  291. /* This must be aligned properly to work on many CPU architectures! */
  292. copy->h_aliases = (char**)MEMALIGN(bufptr);
  293. /* Figure out how many aliases there are */
  294. for (i = 0; orig->h_aliases[i] != NULL; ++i);
  295. /* Reserve room for the array */
  296. bufptr += (i + 1) * sizeof(char*);
  297. /* Clone all known aliases */
  298. for(i = 0; (str = orig->h_aliases[i]); i++) {
  299. len = strlen(str) + 1;
  300. strncpy(bufptr, str, len);
  301. copy->h_aliases[i] = bufptr;
  302. bufptr += len;
  303. }
  304. /* Terminate the alias list with a NULL */
  305. copy->h_aliases[i] = NULL;
  306. copy->h_addrtype = orig->h_addrtype;
  307. copy->h_length = orig->h_length;
  308. /* align it for (at least) 32bit accesses */
  309. bufptr = (char *)MEMALIGN(bufptr);
  310. copy->h_addr_list = (char**)bufptr;
  311. /* Figure out how many addresses there are */
  312. for (i = 0; orig->h_addr_list[i] != NULL; ++i);
  313. /* Reserve room for the array */
  314. bufptr += (i + 1) * sizeof(char*);
  315. i = 0;
  316. len = orig->h_length;
  317. str = orig->h_addr_list[i];
  318. while (str != NULL) {
  319. memcpy(bufptr, str, len);
  320. copy->h_addr_list[i] = bufptr;
  321. bufptr += len;
  322. str = orig->h_addr_list[++i];
  323. }
  324. copy->h_addr_list[i] = NULL;
  325. return copy;
  326. }
  327. #endif
  328. static char *MakeIP(unsigned long num,char *addr, int addr_len)
  329. {
  330. #if defined(HAVE_INET_NTOA) || defined(HAVE_INET_NTOA_R)
  331. struct in_addr in;
  332. in.s_addr = htonl(num);
  333. #if defined(HAVE_INET_NTOA_R)
  334. inet_ntoa_r(in,addr,addr_len);
  335. #else
  336. strncpy(addr,inet_ntoa(in),addr_len);
  337. #endif
  338. #else
  339. unsigned char *paddr;
  340. num = htonl(num); /* htonl() added to avoid endian probs */
  341. paddr = (unsigned char *)&num;
  342. sprintf(addr, "%u.%u.%u.%u", paddr[0], paddr[1], paddr[2], paddr[3]);
  343. #endif
  344. return (addr);
  345. }
  346. /* The original code to this function was once stolen from the Dancer source
  347. code, written by Bjorn Reese, it has since been patched and modified
  348. considerably. */
  349. #ifndef INADDR_NONE
  350. #define INADDR_NONE (in_addr_t) ~0
  351. #endif
  352. Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
  353. char *hostname,
  354. int port,
  355. char **bufp)
  356. {
  357. struct hostent *h = NULL;
  358. in_addr_t in;
  359. int ret; /* this variable is unused on several platforms but used on some */
  360. #define CURL_NAMELOOKUP_SIZE 9000
  361. /* Allocate enough memory to hold the full name information structs and
  362. * everything. OSF1 is known to require at least 8872 bytes. The buffer
  363. * required for storing all possible aliases and IP numbers is according to
  364. * Stevens' Unix Network Programming 2nd editor, p. 304: 8192 bytes! */
  365. int *buf = (int *)malloc(CURL_NAMELOOKUP_SIZE);
  366. if(!buf)
  367. return NULL; /* major failure */
  368. *bufp = (char *)buf;
  369. port=0; /* unused in IPv4 code */
  370. ret = 0; /* to prevent the compiler warning */
  371. if ( (in=inet_addr(hostname)) != INADDR_NONE ) {
  372. struct in_addr *addrentry;
  373. h = (struct hostent*)buf;
  374. h->h_addr_list = (char**)(buf + sizeof(*h));
  375. addrentry = (struct in_addr*)(h->h_addr_list + 2);
  376. addrentry->s_addr = in;
  377. h->h_addr_list[0] = (char*)addrentry;
  378. h->h_addr_list[1] = NULL;
  379. h->h_addrtype = AF_INET;
  380. h->h_length = sizeof(*addrentry);
  381. h->h_name = *(h->h_addr_list) + h->h_length;
  382. /* bad one h->h_name = (char*)(h->h_addr_list + h->h_length); */
  383. MakeIP(ntohl(in),h->h_name, CURL_NAMELOOKUP_SIZE - (long)(h->h_name) + (long)buf);
  384. }
  385. #if defined(HAVE_GETHOSTBYNAME_R)
  386. else {
  387. int h_errnop;
  388. /* Workaround for gethostbyname_r bug in qnx nto. It is also _required_
  389. for some of these functions. */
  390. memset(buf, 0, CURL_NAMELOOKUP_SIZE);
  391. #ifdef HAVE_GETHOSTBYNAME_R_5
  392. /* Solaris, IRIX and more */
  393. if ((h = gethostbyname_r(hostname,
  394. (struct hostent *)buf,
  395. (char *)buf + sizeof(struct hostent),
  396. CURL_NAMELOOKUP_SIZE - sizeof(struct hostent),
  397. &h_errnop)) == NULL )
  398. #endif
  399. #ifdef HAVE_GETHOSTBYNAME_R_6
  400. /* Linux */
  401. if( gethostbyname_r(hostname,
  402. (struct hostent *)buf,
  403. (char *)buf + sizeof(struct hostent),
  404. CURL_NAMELOOKUP_SIZE - sizeof(struct hostent),
  405. &h, /* DIFFERENCE */
  406. &h_errnop))
  407. #endif
  408. #ifdef HAVE_GETHOSTBYNAME_R_3
  409. /* AIX, Digital Unix, HPUX 10, more? */
  410. if(CURL_NAMELOOKUP_SIZE >=
  411. (sizeof(struct hostent)+sizeof(struct hostent_data)))
  412. /* August 22nd, 2000: Albert Chin-A-Young brought an updated version
  413. * that should work! September 20: Richard Prescott worked on the buffer
  414. * size dilemma. */
  415. ret = gethostbyname_r(hostname,
  416. (struct hostent *)buf,
  417. (struct hostent_data *)(buf + sizeof(struct hostent)));
  418. else
  419. ret = -1; /* failure, too smallish buffer size */
  420. /* result expected in h */
  421. h = (struct hostent*)buf;
  422. h_errnop= errno; /* we don't deal with this, but set it anyway */
  423. if(ret)
  424. #endif
  425. {
  426. infof(data, "gethostbyname_r(2) failed for %s\n", hostname);
  427. h = NULL; /* set return code to NULL */
  428. free(buf);
  429. *bufp=NULL;
  430. }
  431. #else
  432. else {
  433. if ((h = gethostbyname(hostname)) == NULL ) {
  434. infof(data, "gethostbyname(2) failed for %s\n", hostname);
  435. free(buf);
  436. *bufp=NULL;
  437. }
  438. else
  439. /* we make a copy of the hostent right now, right here, as the
  440. static one we got a pointer to might get removed when we don't
  441. want/expect that */
  442. h = pack_hostent((char *)buf, h);
  443. #endif
  444. }
  445. return (h);
  446. }
  447. #endif /* end of IPv4-specific code */
  448. /*
  449. * local variables:
  450. * eval: (load-file "../curl-mode.el")
  451. * end:
  452. * vim600: fdm=marker
  453. * vim: et sw=2 ts=2 sts=2 tw=78
  454. */