PageRenderTime 24ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/release_2_15_pre1/dnrd/src/relay.c

#
C | 274 lines | 165 code | 37 blank | 72 comment | 43 complexity | c69b8caf7ef37d42de633b30ddbfc84c MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * relay.c - the guts of the program.
  3. *
  4. * Copyright (C) 1998 Brad M. Garcia <garsh@home.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. #if HAVE_CONFIG_H
  21. #include <config.h>
  22. #endif
  23. #include <stdio.h>
  24. #include <sys/types.h>
  25. #include <sys/socket.h>
  26. #include <netinet/in.h>
  27. #include <arpa/inet.h>
  28. #include <errno.h>
  29. #include <sys/time.h>
  30. #include <unistd.h>
  31. #include <string.h>
  32. #include "query.h"
  33. #include "relay.h"
  34. #include "cache.h"
  35. #include "common.h"
  36. #include "tcp.h"
  37. #include "udp.h"
  38. #include "dns.h"
  39. #include "domnode.h"
  40. #ifndef EXCLUDE_MASTER
  41. #include "master.h"
  42. #endif
  43. /* time interval to retry a deactivated server */
  44. #define SINGLE_RETRY 10
  45. /* prepare the dns packet for a not found reply */
  46. char *set_notfound(char *msg, const int len) {
  47. if (len < 3) return NULL;
  48. /* FIXME: host to network should be called here */
  49. /* Set flags QR and AA */
  50. msg[2] |= 0x84;
  51. /* Set flags RA and RCODE=3 */
  52. msg[3] = 0x83;
  53. return msg;
  54. }
  55. /*
  56. * handle_query()
  57. *
  58. * In: fromaddrp - address of the sender of the query.
  59. *
  60. * In/Out: msg - the query on input, the reply on output.
  61. * len - length of the query/reply
  62. *
  63. * Out: dptr - dptr->current contains the server to which to forward the query
  64. *
  65. * Returns: -1 if the query is bogus
  66. * 1 if the query should be forwarded to the srvidx server
  67. * 0 if msg now contains the reply
  68. *
  69. * Takes a single DNS query and determines what to do with it.
  70. * This is common code used for both TCP and UDP.
  71. *
  72. * Assumptions: There is only one request per message.
  73. */
  74. int handle_query(const struct sockaddr_in *fromaddrp, char *msg, int *len,
  75. domnode_t **dptr)
  76. {
  77. int replylen;
  78. short int * flagp = &((short int *)msg)[1]; /* pointer to flags */
  79. domnode_t *d;
  80. if (opt_debug) {
  81. char cname_buf[256];
  82. sprintf_cname(&msg[12], *len-12, cname_buf, 256);
  83. log_debug("Received DNS query for \"%s\"", cname_buf);
  84. if (dump_dnspacket("query", msg, *len) < 0)
  85. log_debug("Format error");
  86. }
  87. /* First flags check. If Z flag, QR or RCODE is set, just ignore
  88. * the request. According to rfc1035 4.1.1 Z flag must be zero in
  89. * all queries and responses. We should also not have any RCODE
  90. */
  91. if ( ntohs(*flagp) & (MASK_Z + MASK_QR + MASK_RCODE) ) {
  92. log_debug("QR, Z or RCODE was set. Ignoring query");
  93. return(-1);
  94. }
  95. #ifndef EXCLUDE_MASTER
  96. /* First, check to see if we are master server */
  97. if ((replylen = master_lookup(msg, *len)) > 0) {
  98. log_debug("Replying to query as master");
  99. *len = replylen;
  100. return 0;
  101. }
  102. #endif
  103. /* Next, see if we have the answer cached */
  104. if ((replylen = cache_lookup(msg, *len)) > 0) {
  105. log_debug("Replying to query with cached answer.");
  106. *len = replylen;
  107. return 0;
  108. }
  109. /* get the server list for this domain */
  110. d=search_subdomnode(domain_list, &msg[12], *len);
  111. if (no_srvlist(d->srvlist)) {
  112. /* there is no servers for this domain, reply with "entry not found" */
  113. log_debug("Replying to query with \"entry not found\"");
  114. if (!set_notfound(msg, *len)) return -1;
  115. return 0;
  116. }
  117. if (d->roundrobin) set_current(d, next_active(d));
  118. /* Send to a server until it "times out". */
  119. if (d->current) {
  120. time_t now = time(NULL);
  121. if ((d->current->send_time == 0)) {
  122. d->current->send_time = now;
  123. }
  124. else if (now - d->current->send_time > forward_timeout) {
  125. deactivate_current(d);
  126. }
  127. if (d->current) {
  128. log_debug("Forwarding the query to DNS server %s",
  129. inet_ntoa(d->current->addr.sin_addr));
  130. } else {
  131. log_debug("All servers deactivated. Replying with \"entry not found\"");
  132. if (!set_notfound(msg, *len)) return -1;
  133. return 0;
  134. }
  135. } else {
  136. log_debug("All servers deactivated. Replying with \"entry not found\"");
  137. if (!set_notfound(msg, *len)) return -1;
  138. return 0;
  139. }
  140. *dptr = d;
  141. return 1;
  142. }
  143. /* Check if any deactivated server are back online again */
  144. static void reactivate_servers(int interval) {
  145. time_t now=time(NULL);
  146. static int last_try = 0;
  147. domnode_t *d = domain_list;
  148. /* srvnode_t *s;*/
  149. if (!last_try) last_try = now;
  150. /* check for reactivate servers */
  151. if ( (now - last_try < interval) || no_srvlist(d->srvlist) )
  152. return;
  153. last_try = now;
  154. do {
  155. retry_srvlist(d, SINGLE_RETRY);
  156. if (!d->roundrobin) {
  157. /* find the first active server in serverlist */
  158. d->current=NULL;
  159. d->current=next_active(d);
  160. }
  161. } while ((d = d->next) != domain_list);
  162. }
  163. /*
  164. * run()
  165. *
  166. * Abstract: This function runs continuously, waiting for packets to arrive
  167. * and processing them accordingly.
  168. */
  169. void run()
  170. {
  171. int maxsock;
  172. struct timeval tout;
  173. fd_set fdmask;
  174. fd_set fds;
  175. int retn;
  176. /* int i, j;*/
  177. domnode_t *d = domain_list;
  178. srvnode_t *s;
  179. FD_ZERO(&fdmask);
  180. FD_SET(isock, &fdmask);
  181. #ifdef ENABLE_TCP
  182. FD_SET(tcpsock, &fdmask);
  183. maxsock = (tcpsock > isock) ? tcpsock : isock;
  184. #else
  185. maxsock = isock;
  186. #endif
  187. do {
  188. if ((s=d->srvlist)) {
  189. while ((s=s->next) != d->srvlist) {
  190. if (maxsock < s->sock) maxsock = s->sock;
  191. FD_SET(s->sock, &fdmask);
  192. s->send_time = 0;
  193. s->send_count = 0;
  194. }
  195. }
  196. } while ((d=d->next) != domain_list);
  197. maxsock++;
  198. while(1) {
  199. tout.tv_sec = select_timeout;
  200. tout.tv_usec = 0;
  201. fds = fdmask;
  202. /* Wait for input or timeout */
  203. retn = select(maxsock, &fds, 0, 0, &tout);
  204. /* Expire lookups from the cache */
  205. cache_expire();
  206. #ifndef EXCLUDE_MASTER
  207. /* Reload the master database if neccessary */
  208. master_reinit();
  209. #endif
  210. /* Remove old unanswered queries */
  211. dnsquery_timeout(60);
  212. /* reactivate servers */
  213. reactivate_servers(10);
  214. /* Handle errors */
  215. if (retn < 0) {
  216. log_msg(LOG_ERR, "select returned %s", strerror(errno));
  217. continue;
  218. }
  219. else if (retn == 0) {
  220. continue; /* nothing to do */
  221. }
  222. /* Check for replies to DNS queries */
  223. d=domain_list;
  224. do {
  225. if ((s=d->srvlist)) {
  226. while ((s=s->next) != d->srvlist)
  227. if (FD_ISSET(s->sock, &fds)) handle_udpreply(s);
  228. }
  229. } while ((d=d->next) != domain_list);
  230. #ifdef ENABLE_TCP
  231. /* Check for incoming TCP requests */
  232. if (FD_ISSET(tcpsock, &fds)) handle_tcprequest();
  233. #endif
  234. /* Check for new DNS queries */
  235. if (FD_ISSET(isock, &fds)) handle_udprequest();
  236. }
  237. }