PageRenderTime 53ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/irc_res.c

https://bitbucket.org/rizon/ircd/
C | 936 lines | 644 code | 98 blank | 194 comment | 122 complexity | 0d2ec3a0cc3c17097b698ee35ebc1d61 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. /*
  2. * A rewrite of Darren Reeds original res.c As there is nothing
  3. * left of Darrens original code, this is now licensed by the hybrid group.
  4. * (Well, some of the function names are the same, and bits of the structs..)
  5. * You can use it where it is useful, free even. Buy us a beer and stuff.
  6. *
  7. * The authors takes no responsibility for any damage or loss
  8. * of property which results from the use of this software.
  9. *
  10. * $Id: irc_res.c 465 2006-12-28 02:31:10Z jon $
  11. *
  12. * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code,
  13. * added callbacks and reference counting of returned hostents.
  14. * --Bleep (Thomas Helvey <tomh@inxpress.net>)
  15. *
  16. * This was all needlessly complicated for irc. Simplified. No more hostent
  17. * All we really care about is the IP -> hostname mappings. Thats all.
  18. *
  19. * Apr 28, 2003 --cryogen and Dianora
  20. */
  21. #include "stdinc.h"
  22. #include "tools.h"
  23. #include "client.h"
  24. #include "list.h"
  25. #include "common.h"
  26. #include "event.h"
  27. #include "irc_string.h"
  28. #include "sprintf_irc.h"
  29. #include "ircd.h"
  30. #include "numeric.h"
  31. #include "restart.h"
  32. #include "fdlist.h"
  33. #include "fileio.h" /* for fbopen / fbclose / fbputs */
  34. #include "s_bsd.h"
  35. #include "s_log.h"
  36. #include "send.h"
  37. #include "memory.h"
  38. #include "irc_res.h"
  39. #include "irc_reslib.h"
  40. #include "irc_getnameinfo.h"
  41. #if (CHAR_BIT != 8)
  42. #error this code needs to be able to address individual octets
  43. #endif
  44. static PF res_readreply;
  45. #define MAXPACKET 1024 /* rfc sez 512 but we expand names so ... */
  46. #define RES_MAXALIASES 35 /* maximum aliases allowed */
  47. #define RES_MAXADDRS 35 /* maximum addresses allowed */
  48. #define AR_TTL 600 /* TTL in seconds for dns cache entries */
  49. /* RFC 1104/1105 wasn't very helpful about what these fields
  50. * should be named, so for now, we'll just name them this way.
  51. * we probably should look at what named calls them or something.
  52. */
  53. #define TYPE_SIZE (size_t)2
  54. #define CLASS_SIZE (size_t)2
  55. #define TTL_SIZE (size_t)4
  56. #define RDLENGTH_SIZE (size_t)2
  57. #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
  58. typedef enum
  59. {
  60. REQ_IDLE, /* We're doing not much at all */
  61. REQ_PTR, /* Looking up a PTR */
  62. REQ_A, /* Looking up an A, possibly because AAAA failed */
  63. #ifdef IPV6
  64. REQ_AAAA, /* Looking up an AAAA */
  65. #endif
  66. REQ_CNAME, /* We got a CNAME in response, we better get a real answer next */
  67. REQ_INT /* ip6.arpa failed, falling back to ip6.int */
  68. } request_state;
  69. struct reslist
  70. {
  71. dlink_node node;
  72. int id;
  73. int sent; /* number of requests sent */
  74. request_state state; /* State the resolver machine is in */
  75. time_t ttl;
  76. char type;
  77. char retries; /* retry counter */
  78. char sends; /* number of sends (>1 means resent) */
  79. char resend; /* send flag. 0 == dont resend */
  80. time_t sentat;
  81. time_t timeout;
  82. struct irc_ssaddr addr;
  83. char *name;
  84. struct DNSQuery *query; /* query callback for this request */
  85. };
  86. static fde_t ResolverFileDescriptor;
  87. static dlink_list request_list = { NULL, NULL, 0 };
  88. static void rem_request(struct reslist *request);
  89. static struct reslist *make_request(struct DNSQuery *query);
  90. static void do_query_name(struct DNSQuery *query, const char *name, struct reslist *request, int);
  91. static void do_query_number(struct DNSQuery *query,
  92. const struct irc_ssaddr *, struct reslist *request);
  93. static void query_name(const char *name, int query_class, int query_type, struct reslist *request);
  94. static int send_res_msg(const char *buf, int len, int count);
  95. static void resend_query(struct reslist *request);
  96. static int proc_answer(struct reslist *request, HEADER * header, char *, char *);
  97. static struct reslist *find_id(int id);
  98. static struct DNSReply *make_dnsreply(struct reslist *request);
  99. extern struct irc_ssaddr irc_nsaddr_list[IRCD_MAXNS];
  100. extern int irc_nscount;
  101. extern char irc_domain[HOSTLEN + 1];
  102. /*
  103. * int
  104. * res_ourserver(inp)
  105. * looks up "inp" in irc_nsaddr_list[]
  106. * returns:
  107. * 0 : not found
  108. * >0 : found
  109. * author:
  110. * paul vixie, 29may94
  111. * revised for ircd, cryogen(stu) may03
  112. */
  113. static int
  114. res_ourserver(const struct irc_ssaddr *inp)
  115. {
  116. #ifdef IPV6
  117. struct sockaddr_in6 *v6;
  118. struct sockaddr_in6 *v6in = (struct sockaddr_in6 *) inp;
  119. #endif
  120. struct sockaddr_in *v4;
  121. struct sockaddr_in *v4in = (struct sockaddr_in *) inp;
  122. int ns;
  123. for(ns = 0; ns < irc_nscount; ns++)
  124. {
  125. const struct irc_ssaddr *srv = &irc_nsaddr_list[ns];
  126. #ifdef IPV6
  127. v6 = (struct sockaddr_in6 *) srv;
  128. #endif
  129. v4 = (struct sockaddr_in *) srv;
  130. /* could probably just memcmp(srv, inp, srv.ss_len) here
  131. * but we'll air on the side of caution - stu
  132. *
  133. */
  134. switch (srv->ss.ss_family)
  135. {
  136. #ifdef IPV6
  137. case AF_INET6:
  138. if(srv->ss.ss_family == inp->ss.ss_family)
  139. if(v6->sin6_port == v6in->sin6_port)
  140. if((memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr,
  141. sizeof(struct in6_addr)) == 0) ||
  142. (memcmp(&v6->sin6_addr.s6_addr, &in6addr_any,
  143. sizeof(struct in6_addr)) == 0))
  144. return (1);
  145. break;
  146. #endif
  147. case AF_INET:
  148. if(srv->ss.ss_family == inp->ss.ss_family)
  149. if(v4->sin_port == v4in->sin_port)
  150. if((v4->sin_addr.s_addr == INADDR_ANY) ||
  151. (v4->sin_addr.s_addr == v4in->sin_addr.s_addr))
  152. return (1);
  153. break;
  154. default:
  155. break;
  156. }
  157. }
  158. return (0);
  159. }
  160. /*
  161. * timeout_query_list - Remove queries from the list which have been
  162. * there too long without being resolved.
  163. */
  164. static time_t
  165. timeout_query_list(time_t now)
  166. {
  167. dlink_node *ptr;
  168. dlink_node *next_ptr;
  169. struct reslist *request;
  170. time_t next_time = 0;
  171. time_t timeout = 0;
  172. DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
  173. {
  174. request = ptr->data;
  175. timeout = request->sentat + request->timeout;
  176. if(now >= timeout)
  177. {
  178. if(--request->retries <= 0)
  179. {
  180. (*request->query->callback) (request->query->ptr, NULL);
  181. rem_request(request);
  182. continue;
  183. }
  184. else
  185. {
  186. request->sentat = now;
  187. request->timeout += request->timeout;
  188. resend_query(request);
  189. }
  190. }
  191. if((next_time == 0) || timeout < next_time)
  192. {
  193. next_time = timeout;
  194. }
  195. }
  196. return ((next_time > now) ? next_time : (now + AR_TTL));
  197. }
  198. /*
  199. * timeout_resolver - check request list
  200. */
  201. static void
  202. timeout_resolver(void *notused)
  203. {
  204. timeout_query_list(CurrentTime);
  205. }
  206. /*
  207. * start_resolver - do everything we need to read the resolv.conf file
  208. * and initialize the resolver file descriptor if needed
  209. */
  210. static void
  211. start_resolver(void)
  212. {
  213. irc_res_init();
  214. if(!ResolverFileDescriptor.flags.open)
  215. {
  216. if(comm_open(&ResolverFileDescriptor, irc_nsaddr_list[0].ss.ss_family,
  217. SOCK_DGRAM, 0, "Resolver socket") == -1)
  218. return;
  219. /* At the moment, the resolver FD data is global .. */
  220. comm_setselect(&ResolverFileDescriptor, COMM_SELECT_READ, res_readreply, NULL, 0);
  221. eventAdd("timeout_resolver", timeout_resolver, NULL, 1);
  222. }
  223. }
  224. /*
  225. * init_resolver - initialize resolver and resolver library
  226. */
  227. void
  228. init_resolver(void)
  229. {
  230. #ifdef HAVE_SRAND48
  231. srand48(CurrentTime);
  232. #endif
  233. memset(&ResolverFileDescriptor, 0, sizeof(fde_t));
  234. start_resolver();
  235. }
  236. /*
  237. * restart_resolver - reread resolv.conf, reopen socket
  238. */
  239. void
  240. restart_resolver(void)
  241. {
  242. fd_close(&ResolverFileDescriptor);
  243. eventDelete(timeout_resolver, NULL); /* -ddosen */
  244. start_resolver();
  245. }
  246. /*
  247. * add_local_domain - Add the domain to hostname, if it is missing
  248. * (as suggested by eps@TOASTER.SFSU.EDU)
  249. */
  250. void
  251. add_local_domain(char *hname, size_t size)
  252. {
  253. /* try to fix up unqualified names
  254. */
  255. if(strchr(hname, '.') == NULL)
  256. {
  257. if(irc_domain[0])
  258. {
  259. size_t len = strlen(hname);
  260. if((strlen(irc_domain) + len + 2) < size)
  261. {
  262. hname[len++] = '.';
  263. strcpy(hname + len, irc_domain);
  264. }
  265. }
  266. }
  267. }
  268. /*
  269. * rem_request - remove a request from the list.
  270. * This must also free any memory that has been allocated for
  271. * temporary storage of DNS results.
  272. */
  273. static void
  274. rem_request(struct reslist *request)
  275. {
  276. dlinkDelete(&request->node, &request_list);
  277. MyFree(request->name);
  278. MyFree(request);
  279. }
  280. /*
  281. * make_request - Create a DNS request record for the server.
  282. */
  283. static struct reslist *
  284. make_request(struct DNSQuery *query)
  285. {
  286. struct reslist *request;
  287. request = (struct reslist *) MyMalloc(sizeof(struct reslist));
  288. request->sentat = CurrentTime;
  289. request->retries = 2;
  290. request->resend = 1;
  291. request->timeout = 4; /* start at 4 and exponential inc. */
  292. request->query = query;
  293. request->state = REQ_IDLE;
  294. dlinkAdd(request, &request->node, &request_list);
  295. return (request);
  296. }
  297. /*
  298. * delete_resolver_queries - cleanup outstanding queries
  299. * for which there no longer exist clients or conf lines.
  300. */
  301. void
  302. delete_resolver_queries(const struct DNSQuery *query)
  303. {
  304. dlink_node *ptr;
  305. dlink_node *next_ptr;
  306. struct reslist *request;
  307. DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
  308. {
  309. if((request = ptr->data) != NULL)
  310. {
  311. if(query == request->query)
  312. rem_request(request);
  313. }
  314. }
  315. }
  316. /*
  317. * send_res_msg - sends msg to all nameservers found in the "_res" structure.
  318. * This should reflect /etc/resolv.conf. We will get responses
  319. * which arent needed but is easier than checking to see if nameserver
  320. * isnt present. Returns number of messages successfully sent to
  321. * nameservers or -1 if no successful sends.
  322. */
  323. static int
  324. send_res_msg(const char *msg, int len, int rcount)
  325. {
  326. int i;
  327. int sent = 0;
  328. int max_queries = IRCD_MIN(irc_nscount, rcount);
  329. /* RES_PRIMARY option is not implemented
  330. * if (res.options & RES_PRIMARY || 0 == max_queries)
  331. */
  332. if(max_queries == 0)
  333. max_queries = 1;
  334. for(i = 0; i < max_queries; i++)
  335. {
  336. if(sendto(ResolverFileDescriptor.fd, msg, len, 0,
  337. (struct sockaddr *) &(irc_nsaddr_list[i]),
  338. irc_nsaddr_list[i].ss_len) == len)
  339. ++sent;
  340. }
  341. return (sent);
  342. }
  343. /*
  344. * find_id - find a dns request id (id is determined by dn_mkquery)
  345. */
  346. static struct reslist *
  347. find_id(int id)
  348. {
  349. dlink_node *ptr;
  350. struct reslist *request;
  351. DLINK_FOREACH(ptr, request_list.head)
  352. {
  353. request = ptr->data;
  354. if(request->id == id)
  355. return (request);
  356. }
  357. return (NULL);
  358. }
  359. /*
  360. * gethost_byname_type - get host address from name
  361. *
  362. */
  363. void
  364. gethost_byname_type(const char *name, struct DNSQuery *query, int type)
  365. {
  366. assert(name != 0);
  367. do_query_name(query, name, NULL, type);
  368. }
  369. /*
  370. * gethost_byname - wrapper for _type - send T_AAAA first if IPV6 supported
  371. */
  372. void
  373. gethost_byname(const char *name, struct DNSQuery *query)
  374. {
  375. #ifdef IPV6
  376. gethost_byname_type(name, query, T_AAAA);
  377. #else
  378. gethost_byname_type(name, query, T_A);
  379. #endif
  380. }
  381. /*
  382. * gethost_byaddr - get host name from address
  383. */
  384. void
  385. gethost_byaddr(const struct irc_ssaddr *addr, struct DNSQuery *query)
  386. {
  387. do_query_number(query, addr, NULL);
  388. }
  389. /*
  390. * do_query_name - nameserver lookup name
  391. */
  392. static void
  393. do_query_name(struct DNSQuery *query, const char *name, struct reslist *request, int type)
  394. {
  395. char host_name[HOSTLEN + 1];
  396. strlcpy(host_name, name, HOSTLEN);
  397. add_local_domain(host_name, HOSTLEN);
  398. if(request == NULL)
  399. {
  400. request = make_request(query);
  401. request->name = (char *) MyMalloc(strlen(host_name) + 1);
  402. request->type = type;
  403. strcpy(request->name, host_name);
  404. #ifdef IPV6
  405. if(type == T_A)
  406. request->state = REQ_A;
  407. else
  408. request->state = REQ_AAAA;
  409. #else
  410. request->state = REQ_A;
  411. #endif
  412. }
  413. request->type = type;
  414. query_name(host_name, C_IN, type, request);
  415. }
  416. /*
  417. * do_query_number - Use this to do reverse IP# lookups.
  418. */
  419. static void
  420. do_query_number(struct DNSQuery *query, const struct irc_ssaddr *addr, struct reslist *request)
  421. {
  422. char ipbuf[128];
  423. const unsigned char *cp;
  424. #ifdef IPV6
  425. const char *intarpa;
  426. #endif
  427. if(addr->ss.ss_family == AF_INET)
  428. {
  429. struct sockaddr_in *v4 = (struct sockaddr_in *) addr;
  430. cp = (const unsigned char *) &v4->sin_addr.s_addr;
  431. ircsprintf(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
  432. (unsigned int) (cp[3]), (unsigned int) (cp[2]),
  433. (unsigned int) (cp[1]), (unsigned int) (cp[0]));
  434. }
  435. #ifdef IPV6
  436. else if(addr->ss.ss_family == AF_INET6)
  437. {
  438. struct sockaddr_in6 *v6 = (struct sockaddr_in6 *) addr;
  439. cp = (const unsigned char *) &v6->sin6_addr.s6_addr;
  440. if(request != NULL && request->state == REQ_INT)
  441. intarpa = "int";
  442. else
  443. intarpa = "arpa";
  444. (void) sprintf(ipbuf, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
  445. "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.%s.",
  446. (unsigned int) (cp[15] & 0xf), (unsigned int) (cp[15] >> 4),
  447. (unsigned int) (cp[14] & 0xf), (unsigned int) (cp[14] >> 4),
  448. (unsigned int) (cp[13] & 0xf), (unsigned int) (cp[13] >> 4),
  449. (unsigned int) (cp[12] & 0xf), (unsigned int) (cp[12] >> 4),
  450. (unsigned int) (cp[11] & 0xf), (unsigned int) (cp[11] >> 4),
  451. (unsigned int) (cp[10] & 0xf), (unsigned int) (cp[10] >> 4),
  452. (unsigned int) (cp[9] & 0xf), (unsigned int) (cp[9] >> 4),
  453. (unsigned int) (cp[8] & 0xf), (unsigned int) (cp[8] >> 4),
  454. (unsigned int) (cp[7] & 0xf), (unsigned int) (cp[7] >> 4),
  455. (unsigned int) (cp[6] & 0xf), (unsigned int) (cp[6] >> 4),
  456. (unsigned int) (cp[5] & 0xf), (unsigned int) (cp[5] >> 4),
  457. (unsigned int) (cp[4] & 0xf), (unsigned int) (cp[4] >> 4),
  458. (unsigned int) (cp[3] & 0xf), (unsigned int) (cp[3] >> 4),
  459. (unsigned int) (cp[2] & 0xf), (unsigned int) (cp[2] >> 4),
  460. (unsigned int) (cp[1] & 0xf), (unsigned int) (cp[1] >> 4),
  461. (unsigned int) (cp[0] & 0xf), (unsigned int) (cp[0] >> 4), intarpa);
  462. }
  463. #endif
  464. if(request == NULL)
  465. {
  466. request = make_request(query);
  467. request->type = T_PTR;
  468. memcpy(&request->addr, addr, sizeof(struct irc_ssaddr));
  469. request->name = (char *) MyMalloc(HOSTLEN + 1);
  470. }
  471. query_name(ipbuf, C_IN, T_PTR, request);
  472. }
  473. /*
  474. * query_name - generate a query based on class, type and name.
  475. */
  476. static void
  477. query_name(const char *name, int query_class, int type, struct reslist *request)
  478. {
  479. char buf[MAXPACKET];
  480. int request_len = 0;
  481. memset(buf, 0, sizeof(buf));
  482. if((request_len = irc_res_mkquery(name, query_class, type,
  483. (unsigned char *) buf, sizeof(buf))) > 0)
  484. {
  485. HEADER *header = (HEADER *) buf;
  486. #ifndef HAVE_LRAND48
  487. int k = 0;
  488. struct timeval tv;
  489. #endif
  490. /*
  491. * generate an unique id
  492. * NOTE: we don't have to worry about converting this to and from
  493. * network byte order, the nameserver does not interpret this value
  494. * and returns it unchanged
  495. */
  496. #ifdef HAVE_LRAND48
  497. do
  498. {
  499. header->id = (header->id + lrand48()) & 0xffff;
  500. }
  501. while(find_id(header->id));
  502. #else
  503. gettimeofday(&tv, NULL);
  504. do
  505. {
  506. header->id = (header->id + k + tv.tv_usec) & 0xffff;
  507. k++;
  508. }
  509. while(find_id(header->id));
  510. #endif /* HAVE_LRAND48 */
  511. request->id = header->id;
  512. ++request->sends;
  513. request->sent += send_res_msg(buf, request_len, request->sends);
  514. }
  515. }
  516. static void
  517. resend_query(struct reslist *request)
  518. {
  519. if(request->resend == 0)
  520. return;
  521. switch (request->type)
  522. {
  523. case T_PTR:
  524. do_query_number(NULL, &request->addr, request);
  525. break;
  526. case T_A:
  527. do_query_name(NULL, request->name, request, request->type);
  528. break;
  529. #ifdef IPV6
  530. case T_AAAA:
  531. /* didnt work, try A */
  532. if(request->state == REQ_AAAA)
  533. do_query_name(NULL, request->name, request, T_A);
  534. #endif
  535. default:
  536. break;
  537. }
  538. }
  539. /*
  540. * proc_answer - process name server reply
  541. */
  542. static int
  543. proc_answer(struct reslist *request, HEADER * header, char *buf, char *eob)
  544. {
  545. char hostbuf[HOSTLEN + 100]; /* working buffer */
  546. unsigned char *current; /* current position in buf */
  547. int query_class; /* answer class */
  548. int type; /* answer type */
  549. int n; /* temp count */
  550. int rd_length;
  551. struct sockaddr_in *v4; /* conversion */
  552. #ifdef IPV6
  553. struct sockaddr_in6 *v6;
  554. #endif
  555. current = (unsigned char *) buf + sizeof(HEADER);
  556. for(; header->qdcount > 0; --header->qdcount)
  557. {
  558. if((n = irc_dn_skipname(current, (unsigned char *) eob)) < 0)
  559. break;
  560. current += (size_t) n + QFIXEDSZ;
  561. }
  562. /*
  563. * process each answer sent to us blech.
  564. */
  565. while(header->ancount > 0 && (char *) current < eob)
  566. {
  567. header->ancount--;
  568. n = irc_dn_expand((unsigned char *) buf, (unsigned char *) eob, current,
  569. hostbuf, sizeof(hostbuf));
  570. if(n < 0)
  571. {
  572. /*
  573. * broken message
  574. */
  575. return (0);
  576. }
  577. else if(n == 0)
  578. {
  579. /*
  580. * no more answers left
  581. */
  582. return (0);
  583. }
  584. hostbuf[HOSTLEN] = '\0';
  585. /* With Address arithmetic you have to be very anal
  586. * this code was not working on alpha due to that
  587. * (spotted by rodder/jailbird/dianora)
  588. */
  589. current += (size_t) n;
  590. if(!(((char *) current + ANSWER_FIXED_SIZE) < eob))
  591. break;
  592. type = irc_ns_get16(current);
  593. current += TYPE_SIZE;
  594. query_class = irc_ns_get16(current);
  595. current += CLASS_SIZE;
  596. request->ttl = irc_ns_get32(current);
  597. current += TTL_SIZE;
  598. rd_length = irc_ns_get16(current);
  599. current += RDLENGTH_SIZE;
  600. /*
  601. * Wait to set request->type until we verify this structure
  602. */
  603. switch (type)
  604. {
  605. case T_A:
  606. if(request->type != T_A)
  607. return (0);
  608. /*
  609. * check for invalid rd_length or too many addresses
  610. */
  611. if(rd_length != sizeof(struct in_addr))
  612. return (0);
  613. v4 = (struct sockaddr_in *) &request->addr;
  614. request->addr.ss_len = sizeof(struct sockaddr_in);
  615. v4->sin_family = AF_INET;
  616. memcpy(&v4->sin_addr, current, sizeof(struct in_addr));
  617. return (1);
  618. break;
  619. #ifdef IPV6
  620. case T_AAAA:
  621. if(request->type != T_AAAA)
  622. return (0);
  623. if(rd_length != sizeof(struct in6_addr))
  624. return (0);
  625. request->addr.ss_len = sizeof(struct sockaddr_in6);
  626. v6 = (struct sockaddr_in6 *) &request->addr;
  627. v6->sin6_family = AF_INET6;
  628. memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr));
  629. return (1);
  630. break;
  631. #endif
  632. case T_PTR:
  633. if(request->type != T_PTR)
  634. return (0);
  635. n = irc_dn_expand((unsigned char *) buf, (unsigned char *) eob,
  636. current, hostbuf, sizeof(hostbuf));
  637. if(n < 0)
  638. return (0); /* broken message */
  639. else if(n == 0)
  640. return (0); /* no more answers left */
  641. strlcpy(request->name, hostbuf, HOSTLEN);
  642. return (1);
  643. break;
  644. case T_CNAME: /* first check we already havent started looking
  645. into a cname */
  646. if(request->type != T_PTR)
  647. return (0);
  648. if(request->state == REQ_CNAME)
  649. {
  650. n = irc_dn_expand((unsigned char *) buf, (unsigned char *) eob,
  651. current, hostbuf, sizeof(hostbuf));
  652. if(n < 0)
  653. return (0);
  654. return (1);
  655. }
  656. request->state = REQ_CNAME;
  657. current += rd_length;
  658. break;
  659. default:
  660. /* XXX I'd rather just throw away the entire bogus thing
  661. * but its possible its just a broken nameserver with still
  662. * valid answers. But lets do some rudimentary logging for now...
  663. */
  664. ilog(L_ERROR, "irc_res.c bogus type %d", type);
  665. break;
  666. }
  667. }
  668. return (1);
  669. }
  670. /*
  671. * res_readreply - read a dns reply from the nameserver and process it.
  672. */
  673. static void
  674. res_readreply(fde_t * fd, void *data)
  675. {
  676. char buf[sizeof(HEADER) + MAXPACKET]
  677. /* Sparc and alpha need 16bit-alignment for accessing header->id
  678. * (which is uint16_t). Because of the header = (HEADER*) buf;
  679. * lateron, this is neeeded. --FaUl
  680. */
  681. #if defined(__sparc__) || defined(__alpha__)
  682. __attribute__ ((aligned(16)))
  683. #endif
  684. ;
  685. HEADER *header;
  686. struct reslist *request = NULL;
  687. struct DNSReply *reply = NULL;
  688. int rc;
  689. int answer_count;
  690. socklen_t len = sizeof(struct irc_ssaddr);
  691. struct irc_ssaddr lsin;
  692. rc = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *) &lsin, &len);
  693. /* Re-schedule a read *after* recvfrom, or we'll be registering
  694. * interest where it'll instantly be ready for read :-) -- adrian
  695. */
  696. comm_setselect(fd, COMM_SELECT_READ, res_readreply, NULL, 0);
  697. /* Better to cast the sizeof instead of rc */
  698. if(rc <= (int) (sizeof(HEADER)))
  699. return;
  700. /*
  701. * convert DNS reply reader from Network byte order to CPU byte order.
  702. */
  703. header = (HEADER *) buf;
  704. header->ancount = ntohs(header->ancount);
  705. header->qdcount = ntohs(header->qdcount);
  706. header->nscount = ntohs(header->nscount);
  707. header->arcount = ntohs(header->arcount);
  708. /*
  709. * response for an id which we have already received an answer for
  710. * just ignore this response.
  711. */
  712. if(0 == (request = find_id(header->id)))
  713. return;
  714. /*
  715. * check against possibly fake replies
  716. */
  717. if(!res_ourserver(&lsin))
  718. return;
  719. if((header->rcode != NO_ERRORS) || (header->ancount == 0))
  720. {
  721. if(NXDOMAIN == header->rcode)
  722. {
  723. /*
  724. * If we havent already tried this, and we're looking up AAAA, try A
  725. * now
  726. */
  727. #ifdef IPV6
  728. if(request->state == REQ_AAAA && request->type == T_AAAA)
  729. {
  730. request->timeout += 4;
  731. resend_query(request);
  732. }
  733. else if(request->type == T_PTR && request->state != REQ_INT &&
  734. request->addr.ss.ss_family == AF_INET6)
  735. {
  736. request->state = REQ_INT;
  737. request->timeout += 4;
  738. request->retries--;
  739. resend_query(request);
  740. }
  741. else /* It's NXDOMAIN but not IPV6 */
  742. #endif
  743. {
  744. /*
  745. * If a bad error was returned, stop here and don't
  746. * send any more (no retries granted).
  747. */
  748. (*request->query->callback) (request->query->ptr, NULL);
  749. rem_request(request);
  750. }
  751. }
  752. else /* Some other error other than NXDOMAIN */
  753. {
  754. /*
  755. * If a bad error was returned, stop here and don't
  756. * send any more (no retries granted).
  757. */
  758. (*request->query->callback) (request->query->ptr, NULL);
  759. rem_request(request);
  760. }
  761. return;
  762. }
  763. /*
  764. * If this fails there was an error decoding the received packet,
  765. * try it again and hope it works the next time.
  766. */
  767. answer_count = proc_answer(request, header, buf, buf + rc);
  768. if(answer_count)
  769. {
  770. if(request->type == T_PTR)
  771. {
  772. if(request->name == NULL)
  773. {
  774. /*
  775. * got a PTR response with no name, something bogus is happening
  776. * don't bother trying again, the client address doesn't resolve
  777. */
  778. (*request->query->callback) (request->query->ptr, reply);
  779. rem_request(request);
  780. return;
  781. }
  782. /*
  783. * Lookup the 'authoritative' name that we were given for the
  784. * ip#.
  785. *
  786. */
  787. #ifdef IPV6
  788. if(request->addr.ss.ss_family == AF_INET6)
  789. gethost_byname_type(request->name, request->query, T_AAAA);
  790. else
  791. #endif
  792. gethost_byname_type(request->name, request->query, T_A);
  793. rem_request(request);
  794. }
  795. else
  796. {
  797. /*
  798. * got a name and address response, client resolved
  799. */
  800. reply = make_dnsreply(request);
  801. (*request->query->callback) (request->query->ptr, reply);
  802. MyFree(reply);
  803. rem_request(request);
  804. }
  805. }
  806. else if(!request->sent)
  807. {
  808. /* XXX - we got a response for a query we didn't send with a valid id?
  809. * this should never happen, bail here and leave the client unresolved
  810. */
  811. assert(0);
  812. /* XXX don't leak it */
  813. rem_request(request);
  814. }
  815. }
  816. static struct DNSReply *
  817. make_dnsreply(struct reslist *request)
  818. {
  819. struct DNSReply *cp;
  820. assert(request != 0);
  821. cp = (struct DNSReply *) MyMalloc(sizeof(struct DNSReply));
  822. cp->h_name = request->name;
  823. memcpy(&cp->addr, &request->addr, sizeof(cp->addr));
  824. return (cp);
  825. }
  826. void
  827. report_dns_servers(struct Client *source_p)
  828. {
  829. int i;
  830. char ipaddr[HOSTIPLEN];
  831. for(i = 0; i < irc_nscount; i++)
  832. {
  833. irc_getnameinfo((struct sockaddr *) &(irc_nsaddr_list[i]),
  834. irc_nsaddr_list[i].ss_len, ipaddr, HOSTIPLEN, NULL, 0,
  835. NI_NUMERICHOST);
  836. sendto_one(source_p, form_str(RPL_STATSALINE), me.name, source_p->name, ipaddr);
  837. }
  838. }