resolver.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /*
  2. * resolver.c:
  3. *
  4. */
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8. #include <arpa/inet.h>
  9. #include <pthread.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <netdb.h>
  13. #include <errno.h>
  14. #include <string.h>
  15. #include <unistd.h>
  16. #include "ns_hash.h"
  17. #include "iftop.h"
  18. #include "threadprof.h"
  19. #include "options.h"
  20. #define RESOLVE_QUEUE_LENGTH 20
  21. struct addr_storage {
  22. int af; /* AF_INET or AF_INET6 */
  23. int len; /* sizeof(struct in_addr or in6_addr) */
  24. union {
  25. struct in_addr addr4;
  26. struct in6_addr addr6;
  27. } addr;
  28. #define as_addr4 addr.addr4
  29. #define as_addr6 addr.addr6
  30. };
  31. struct addr_storage resolve_queue[RESOLVE_QUEUE_LENGTH];
  32. pthread_cond_t resolver_queue_cond;
  33. pthread_mutex_t resolver_queue_mutex;
  34. hash_type* ns_hash;
  35. int head;
  36. int tail;
  37. extern options_t options;
  38. /*
  39. * We have a choice of resolver methods. Real computers have getnameinfo or
  40. * gethostbyaddr_r, which are reentrant and therefore thread safe. Other
  41. * machines don't, and so we can use non-reentrant gethostbyaddr and have only
  42. * one resolver thread. Alternatively, we can use the MIT ares asynchronous
  43. * DNS library to do this.
  44. */
  45. #if defined(USE_GETNAMEINFO)
  46. /**
  47. * Implementation of do_resolve for platforms with getaddrinfo.
  48. *
  49. * This is a fairly sane function with a uniform interface which is even --
  50. * shock! -- standardised by POSIX and in RFC 2553. Unfortunately systems such
  51. * as NetBSD break the RFC and implement it in a non-thread-safe fashion, so
  52. * for the moment, the configure script won't try to use it.
  53. */
  54. char *do_resolve(struct addr_storage *addr) {
  55. struct sockaddr_in sin;
  56. struct sockaddr_in6 sin6;
  57. char buf[NI_MAXHOST]; /* 1025 */
  58. int ret;
  59. switch (addr->af) {
  60. case AF_INET:
  61. sin.sin_family = addr->af;
  62. sin.sin_port = 0;
  63. memcpy(&sin.sin_addr, &addr->as_addr4, addr->len);
  64. ret = getnameinfo((struct sockaddr*)&sin, sizeof sin,
  65. buf, sizeof buf, NULL, 0, NI_NAMEREQD);
  66. break;
  67. case AF_INET6:
  68. sin6.sin6_family = addr->af;
  69. sin6.sin6_port = 0;
  70. memcpy(&sin6.sin6_addr, &addr->as_addr6, addr->len);
  71. ret = getnameinfo((struct sockaddr*)&sin6, sizeof sin6,
  72. buf, sizeof buf, NULL, 0, NI_NAMEREQD);
  73. break;
  74. default:
  75. return NULL;
  76. }
  77. if (ret == 0)
  78. return xstrdup(buf);
  79. else
  80. return NULL;
  81. }
  82. #elif defined(USE_GETHOSTBYADDR_R)
  83. /**
  84. * Implementation of do_resolve for platforms with working gethostbyaddr_r
  85. *
  86. * Some implementations of libc choose to implement gethostbyaddr_r as
  87. * a non thread-safe wrapper to gethostbyaddr. An interesting choice...
  88. */
  89. char* do_resolve(struct addr_storage *addr) {
  90. struct hostent hostbuf, *hp = NULL;
  91. size_t hstbuflen = 1024;
  92. char *tmphstbuf;
  93. int res = 0;
  94. int herr;
  95. char * ret = NULL;
  96. /* Allocate buffer, remember to free it to avoid memory leakage. */
  97. tmphstbuf = xmalloc (hstbuflen);
  98. /* nss-myhostname's gethostbyaddr_r() causes an assertion failure if an
  99. * "invalid" (as in outside of IPv4 or IPv6) address family is passed */
  100. if (addr->af == AF_INET || addr->af == AF_INET6) {
  101. /* Some machines have gethostbyaddr_r returning an integer error code; on
  102. * others, it returns a struct hostent*. */
  103. #ifdef GETHOSTBYADDR_R_RETURNS_INT
  104. while ((res = gethostbyaddr_r((char*)&addr->addr, addr->len, addr->af,
  105. &hostbuf, tmphstbuf, hstbuflen,
  106. &hp, &herr)) == ERANGE)
  107. #else
  108. /* ... also assume one fewer argument.... */
  109. while ((hp = gethostbyaddr_r((char*)&addr->addr, addr->len, addr->af,
  110. &hostbuf, tmphstbuf, hstbuflen, &herr)) == NULL
  111. && errno == ERANGE)
  112. #endif
  113. {
  114. /* Enlarge the buffer. */
  115. hstbuflen *= 2;
  116. tmphstbuf = realloc (tmphstbuf, hstbuflen);
  117. }
  118. }
  119. /* Check for errors. */
  120. if (res || hp == NULL) {
  121. /* failed */
  122. /* Leave the unresolved IP in the hash */
  123. }
  124. else {
  125. ret = xstrdup(hp->h_name);
  126. }
  127. xfree(tmphstbuf);
  128. return ret;
  129. }
  130. #elif defined(USE_GETHOSTBYADDR)
  131. /**
  132. * Implementation using gethostbyname. Since this is nonreentrant, we have to
  133. * wrap it in a mutex, losing all benefit of multithreaded resolution.
  134. */
  135. char *do_resolve(struct addr_storage *addr) {
  136. static pthread_mutex_t ghba_mtx = PTHREAD_MUTEX_INITIALIZER;
  137. char *s = NULL;
  138. struct hostent *he;
  139. pthread_mutex_lock(&ghba_mtx);
  140. he = gethostbyaddr((char*)&addr->addr, addr->len, addr->af);
  141. if (he)
  142. s = xstrdup(he->h_name);
  143. pthread_mutex_unlock(&ghba_mtx);
  144. return s;
  145. }
  146. #elif defined(USE_LIBRESOLV)
  147. #include <arpa/nameser.h>
  148. #include <resolv.h>
  149. /**
  150. * libresolv implementation
  151. * resolver functions may not be thread safe
  152. */
  153. char* do_resolve(struct addr_storage *addr) {
  154. char msg[PACKETSZ];
  155. char s[35];
  156. int l;
  157. unsigned char* a;
  158. char * ret = NULL;
  159. if (addr->af != AF_INET)
  160. return NULL;
  161. a = (unsigned char*)&addr->addr;
  162. snprintf(s, 35, "%d.%d.%d.%d.in-addr.arpa.",a[3], a[2], a[1], a[0]);
  163. l = res_search(s, C_IN, T_PTR, msg, PACKETSZ);
  164. if(l != -1) {
  165. ns_msg nsmsg;
  166. ns_rr rr;
  167. if(ns_initparse(msg, l, &nsmsg) != -1) {
  168. int c;
  169. int i;
  170. c = ns_msg_count(nsmsg, ns_s_an);
  171. for(i = 0; i < c; i++) {
  172. if(ns_parserr(&nsmsg, ns_s_an, i, &rr) == 0){
  173. if(ns_rr_type(rr) == T_PTR) {
  174. char buf[256];
  175. ns_name_uncompress(msg, msg + l, ns_rr_rdata(rr), buf, 256);
  176. ret = xstrdup(buf);
  177. }
  178. }
  179. }
  180. }
  181. }
  182. return ret;
  183. }
  184. #elif defined(USE_ARES)
  185. /**
  186. * ares implementation
  187. */
  188. #include <sys/time.h>
  189. #include <ares.h>
  190. #include <arpa/nameser.h>
  191. /* callback function for ares */
  192. struct ares_callback_comm {
  193. struct in_addr *addr;
  194. int result;
  195. char *name;
  196. };
  197. static void do_resolve_ares_callback(void *arg, int status, unsigned char *abuf, int alen) {
  198. struct hostent *he;
  199. struct ares_callback_comm *C;
  200. C = (struct ares_callback_comm*)arg;
  201. if (status == ARES_SUCCESS) {
  202. C->result = 1;
  203. ares_parse_ptr_reply(abuf, alen, C->addr, sizeof *C->addr, AF_INET, &he);
  204. C->name = xstrdup(he->h_name);;
  205. ares_free_hostent(he);
  206. } else {
  207. C->result = -1;
  208. }
  209. }
  210. char *do_resolve(struct addr_storage * addr) {
  211. struct ares_callback_comm C;
  212. char s[35];
  213. unsigned char *a;
  214. ares_channel *chan;
  215. static pthread_mutex_t ares_init_mtx = PTHREAD_MUTEX_INITIALIZER;
  216. static pthread_key_t ares_key;
  217. static int gotkey;
  218. if (addr->af != AF_INET)
  219. return NULL;
  220. /* Make sure we have an ARES channel for this thread. */
  221. pthread_mutex_lock(&ares_init_mtx);
  222. if (!gotkey) {
  223. pthread_key_create(&ares_key, NULL);
  224. gotkey = 1;
  225. }
  226. pthread_mutex_unlock(&ares_init_mtx);
  227. chan = pthread_getspecific(ares_key);
  228. if (!chan) {
  229. chan = xmalloc(sizeof *chan);
  230. pthread_setspecific(ares_key, chan);
  231. if (ares_init(chan) != ARES_SUCCESS) return NULL;
  232. }
  233. a = (unsigned char*)&addr->as_addr4;
  234. sprintf(s, "%d.%d.%d.%d.in-addr.arpa.", a[3], a[2], a[1], a[0]);
  235. C.result = 0;
  236. C.addr = &addr->as_addr4;
  237. ares_query(*chan, s, C_IN, T_PTR, do_resolve_ares_callback, &C);
  238. while (C.result == 0) {
  239. int n;
  240. fd_set readfds, writefds;
  241. struct timeval tv;
  242. FD_ZERO(&readfds);
  243. FD_ZERO(&writefds);
  244. n = ares_fds(*chan, &readfds, &writefds);
  245. ares_timeout(*chan, NULL, &tv);
  246. select(n, &readfds, &writefds, NULL, &tv);
  247. ares_process(*chan, &readfds, &writefds);
  248. }
  249. /* At this stage, the query should be complete. */
  250. switch (C.result) {
  251. case -1:
  252. case 0: /* shouldn't happen */
  253. return NULL;
  254. default:
  255. return C.name;
  256. }
  257. }
  258. #elif defined(USE_FORKING_RESOLVER)
  259. /**
  260. * Resolver which forks a process, then uses gethostbyname.
  261. */
  262. #include <signal.h>
  263. #define NAMESIZE 64
  264. int forking_resolver_worker(int fd) {
  265. while (1) {
  266. struct addr_storage a;
  267. struct hostent *he;
  268. char buf[NAMESIZE] = {0};
  269. if (read(fd, &a, sizeof a) != sizeof a)
  270. return -1;
  271. he = gethostbyaddr((char*)&a.addr, a.len, a.af);
  272. if (he)
  273. strncpy(buf, he->h_name, NAMESIZE - 1);
  274. if (write(fd, buf, NAMESIZE) != NAMESIZE)
  275. return -1;
  276. }
  277. }
  278. char *do_resolve(struct in6_addr *addr) {
  279. struct {
  280. int fd;
  281. pid_t child;
  282. } *workerinfo;
  283. char name[NAMESIZE];
  284. static pthread_mutex_t worker_init_mtx = PTHREAD_MUTEX_INITIALIZER;
  285. static pthread_key_t worker_key;
  286. static int gotkey;
  287. /* If no process exists, we need to spawn one. */
  288. pthread_mutex_lock(&worker_init_mtx);
  289. if (!gotkey) {
  290. pthread_key_create(&worker_key, NULL);
  291. gotkey = 1;
  292. }
  293. pthread_mutex_unlock(&worker_init_mtx);
  294. workerinfo = pthread_getspecific(worker_key);
  295. if (!workerinfo) {
  296. int p[2];
  297. if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, p) == -1)
  298. return NULL;
  299. workerinfo = xmalloc(sizeof *workerinfo);
  300. pthread_setspecific(worker_key, workerinfo);
  301. workerinfo->fd = p[0];
  302. switch (workerinfo->child = fork()) {
  303. case 0:
  304. close(p[0]);
  305. _exit(forking_resolver_worker(p[1]));
  306. case -1:
  307. close(p[0]);
  308. close(p[1]);
  309. return NULL;
  310. default:
  311. close(p[1]);
  312. }
  313. }
  314. /* Now have a worker to which we can write requests. */
  315. if (write(workerinfo->fd, addr, sizeof *addr) != sizeof *addr
  316. || read(workerinfo->fd, name, NAMESIZE) != NAMESIZE) {
  317. /* Something went wrong. Just kill the child and get on with it. */
  318. kill(workerinfo->child, SIGKILL);
  319. wait(NULL);
  320. close(workerinfo->fd);
  321. xfree(workerinfo);
  322. pthread_setspecific(worker_key, NULL);
  323. *name = 0;
  324. }
  325. if (!*name)
  326. return NULL;
  327. else
  328. return xstrdup(name);
  329. }
  330. #else
  331. # warning No name resolution method specified; name resolution will not work
  332. char *do_resolve(struct addr_storage *addr) {
  333. return NULL;
  334. }
  335. #endif
  336. void resolver_worker(void* ptr) {
  337. /* int thread_number = *(int*)ptr;*/
  338. pthread_mutex_lock(&resolver_queue_mutex);
  339. sethostent(1);
  340. while(1) {
  341. /* Wait until we are told that an address has been added to the
  342. * queue. */
  343. pthread_cond_wait(&resolver_queue_cond, &resolver_queue_mutex);
  344. /* Keep resolving until the queue is empty */
  345. while(head != tail) {
  346. char * hostname;
  347. struct addr_storage addr = resolve_queue[tail];
  348. /* mutex always locked at this point */
  349. tail = (tail + 1) % RESOLVE_QUEUE_LENGTH;
  350. pthread_mutex_unlock(&resolver_queue_mutex);
  351. hostname = do_resolve(&addr);
  352. /*
  353. * Store the result in ns_hash
  354. */
  355. pthread_mutex_lock(&resolver_queue_mutex);
  356. if(hostname != NULL) {
  357. char* old;
  358. union {
  359. char **ch_pp;
  360. void **void_pp;
  361. } u_old = { &old };
  362. if(hash_find(ns_hash, &addr, u_old.void_pp) == HASH_STATUS_OK) {
  363. hash_delete(ns_hash, &addr);
  364. xfree(old);
  365. }
  366. hash_insert(ns_hash, &addr, (void*)hostname);
  367. }
  368. }
  369. }
  370. }
  371. void resolver_initialise() {
  372. int* n;
  373. int i;
  374. pthread_t thread;
  375. head = tail = 0;
  376. ns_hash = ns_hash_create();
  377. pthread_mutex_init(&resolver_queue_mutex, NULL);
  378. pthread_cond_init(&resolver_queue_cond, NULL);
  379. for(i = 0; i < 2; i++) {
  380. n = (int*)xmalloc(sizeof *n);
  381. *n = i;
  382. pthread_create(&thread, NULL, (void*)&resolver_worker, (void*)n);
  383. }
  384. }
  385. void resolve(int af, void* addr, char* result, int buflen) {
  386. char* hostname;
  387. union {
  388. char **ch_pp;
  389. void **void_pp;
  390. } u_hostname = { &hostname };
  391. int added = 0;
  392. struct addr_storage *raddr;
  393. if(options.dnsresolution == 1) {
  394. raddr = malloc(sizeof *raddr);
  395. memset(raddr, 0, sizeof *raddr);
  396. raddr->af = af;
  397. raddr->len = (af == AF_INET ? sizeof(struct in_addr)
  398. : sizeof(struct in6_addr));
  399. memcpy(&raddr->addr, addr, raddr->len);
  400. pthread_mutex_lock(&resolver_queue_mutex);
  401. if(hash_find(ns_hash, raddr, u_hostname.void_pp) == HASH_STATUS_OK) {
  402. /* Found => already resolved, or on the queue, no need to keep
  403. * it around */
  404. free(raddr);
  405. }
  406. else {
  407. hostname = xmalloc(INET6_ADDRSTRLEN);
  408. inet_ntop(af, &raddr->addr, hostname, INET6_ADDRSTRLEN);
  409. hash_insert(ns_hash, raddr, hostname);
  410. if(((head + 1) % RESOLVE_QUEUE_LENGTH) == tail) {
  411. /* queue full */
  412. }
  413. else if ((af == AF_INET6)
  414. && (IN6_IS_ADDR_LINKLOCAL(&raddr->as_addr6)
  415. || IN6_IS_ADDR_SITELOCAL(&raddr->as_addr6))) {
  416. /* Link-local and site-local stay numerical. */
  417. }
  418. else {
  419. resolve_queue[head] = *raddr;
  420. head = (head + 1) % RESOLVE_QUEUE_LENGTH;
  421. added = 1;
  422. }
  423. }
  424. pthread_mutex_unlock(&resolver_queue_mutex);
  425. if(added == 1) {
  426. pthread_cond_signal(&resolver_queue_cond);
  427. }
  428. if(result != NULL && buflen > 1) {
  429. strncpy(result, hostname, buflen - 1);
  430. result[buflen - 1] = '\0';
  431. }
  432. }
  433. }