root/src/modules/dns.c

Revision 5a9b91bc0a14543e0995eba973fbeacc05aaee8b, 19.9 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

svn merge -r 327:330 https://labs.omniti.com/reconnoiter/branches/dev/udns .

closes #38

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <netdb.h>
11 #include <errno.h>
12 #include <assert.h>
13 #include <arpa/inet.h>
14
15 #include "noit_module.h"
16 #include "noit_check.h"
17 #include "noit_check_tools.h"
18 #include "utils/noit_log.h"
19 #include "utils/noit_atomic.h"
20 #include "udns/udns.h"
21
22 static void eventer_dns_utm_fn(struct dns_ctx *, int, void *);
23 static int dns_eventer_callback(eventer_t, int, void *, struct timeval *);
24
25 static noit_log_stream_t nlerr = NULL;
26 static noit_log_stream_t nldeb = NULL;
27
28 static noit_hash_table dns_rtypes = NOIT_HASH_EMPTY;
29 static noit_hash_table dns_ctypes = NOIT_HASH_EMPTY;
30
31 static noit_hash_table dns_ctx_store = NOIT_HASH_EMPTY;
32 static pthread_mutex_t dns_ctx_store_lock;
33 typedef struct dns_ctx_handle {
34   char *ns;
35   struct dns_ctx *ctx;
36   noit_atomic32_t refcnt;
37   eventer_t e; /* evetner handling UDP traffic */
38   eventer_t timeout; /* the timeout managed by libudns */
39 } dns_ctx_handle_t;
40
41 static dns_ctx_handle_t *default_ctx_handle = NULL;
42 static void dns_ctx_handle_free(void *vh) {
43   dns_ctx_handle_t *h = vh;
44   assert(h->timeout == NULL);
45   free(h->ns);
46   dns_close(h->ctx);
47   dns_free(h->ctx);
48 }
49 static dns_ctx_handle_t *dns_ctx_alloc(const char *ns) {
50   dns_ctx_handle_t *h = NULL;
51   pthread_mutex_lock(&dns_ctx_store_lock);
52   if(ns == NULL && default_ctx_handle != NULL) {
53     /* special case -- default context */
54     h = default_ctx_handle;
55     noit_atomic_inc32(&h->refcnt);
56     goto bail;
57   }
58   if(ns &&
59      noit_hash_retrieve(&dns_ctx_store, ns, strlen(ns), (void **)&h)) {
60     noit_atomic_inc32(&h->refcnt);
61   }
62   else {
63     int failed = 0;
64     h = calloc(1, sizeof(*h));
65     h->ns = ns ? strdup(ns) : NULL;
66     h->ctx = dns_new(NULL);
67     if(dns_init(h->ctx, 0) != 0) failed++;
68     if(ns) {
69       if(dns_add_serv(h->ctx, NULL) < 0) failed++;
70       if(dns_add_serv(h->ctx, ns) < 0) failed++;
71     }
72     if(dns_open(h->ctx) < 0) failed++;
73     if(failed) {
74       noitL(nlerr, "dns_open failed\n");
75       free(h->ns);
76       free(h);
77       h = NULL;
78       goto bail;
79     }
80     dns_set_tmcbck(h->ctx, eventer_dns_utm_fn, h);
81     h->e = eventer_alloc();
82     h->e->mask = EVENTER_READ | EVENTER_EXCEPTION;
83     h->e->closure = h;
84     h->e->callback = dns_eventer_callback;
85     h->e->fd = dns_sock(h->ctx);
86     eventer_add(h->e);
87     h->refcnt = 1;
88     if(!ns)
89       default_ctx_handle = h;
90     else
91       noit_hash_store(&dns_ctx_store, h->ns, strlen(h->ns), h);
92   }
93  bail:
94   pthread_mutex_unlock(&dns_ctx_store_lock);
95   return h;
96 }
97 static void dns_ctx_release(dns_ctx_handle_t *h) {
98   if(h->ns == NULL) {
99     /* Special case for the default */
100     noit_atomic_dec32(&h->refcnt);
101     return;
102   }
103   pthread_mutex_lock(&dns_ctx_store_lock);
104   if(noit_atomic_dec32(&h->refcnt) == 1) {
105     /* I was the last one */
106     assert(noit_hash_delete(&dns_ctx_store, h->ns, strlen(h->ns),
107                             NULL, dns_ctx_handle_free));
108   }
109   pthread_mutex_unlock(&dns_ctx_store_lock);
110 }
111
112 static noit_hash_table active_events = NOIT_HASH_EMPTY;
113 static pthread_mutex_t active_events_lock;
114
115 typedef struct dns_check_info {
116   stats_t current;
117   int timed_out;
118   noit_module_t *self;
119   noit_check_t *check;
120   eventer_t timeout_event;
121   dns_ctx_handle_t *h;
122   char *error;
123   int nrr;
124
125   /* These make up the query itself */
126   unsigned char dn[DNS_MAXDN];
127   enum dns_class query_ctype;
128   enum dns_type query_rtype;
129 } dns_check_info_t;
130
131 static int __isactive_ci(struct dns_check_info *ci) {
132   struct dns_check_info *u;
133   int exists = 0;
134   pthread_mutex_lock(&active_events_lock);
135   if(noit_hash_retrieve(&active_events, (void *)&ci, sizeof(ci), (void **)&u))
136     exists = 1;
137   pthread_mutex_unlock(&active_events_lock);
138   return exists;
139 }
140 static void __activate_ci(struct dns_check_info *ci) {
141   struct dns_check_info **holder;
142   holder = calloc(1, sizeof(*holder));
143   *holder = ci;
144   pthread_mutex_lock(&active_events_lock);
145   assert(noit_hash_store(&active_events, (void *)holder, sizeof(*holder), ci));
146   pthread_mutex_unlock(&active_events_lock);
147 }
148 static void __deactivate_ci(struct dns_check_info *ci) {
149   pthread_mutex_lock(&active_events_lock);
150   assert(noit_hash_delete(&active_events, (void *)&ci, sizeof(ci), free, NULL));
151   pthread_mutex_unlock(&active_events_lock);
152 }
153
154 static void dns_check_log_results(struct dns_check_info *ci) {
155   struct timeval duration;
156
157   gettimeofday(&ci->current.whence, NULL);
158   sub_timeval(ci->current.whence, ci->check->last_fire_time, &duration);
159   ci->current.duration = duration.tv_sec * 1000 + duration.tv_usec / 1000;
160
161   ci->current.state = (ci->error || ci->nrr == 0) ? NP_BAD : NP_GOOD;
162   ci->current.available = ci->timed_out ? NP_UNAVAILABLE : NP_AVAILABLE;
163   if(ci->error) {
164     ci->current.status = strdup(ci->error);
165   }
166   else if(!ci->current.status) {
167     char buff[48];
168     snprintf(buff, sizeof(buff), "%d %s",
169              ci->nrr, ci->nrr == 1 ? "record" : "records");
170     ci->current.status = strdup(buff);
171   }
172
173   noit_check_set_stats(ci->self, ci->check, &ci->current);
174   if(ci->error) free(ci->error);
175   if(ci->current.status) free(ci->current.status);
176   ci->error = NULL;
177   memset(&ci->current, 0, sizeof(ci->current));
178 }
179
180 static int dns_interpolate_inaddr_arpa(char *buff, int len, const char *ip) {
181   const char *b, *e;
182   char *o = buff;
183   int il;
184   /* This function takes a dot delimited string as input and
185    * reverses the parts split on dot.
186    */
187   il = strlen(ip);
188   if(len <= il) {
189     /* not enough room for ip and '\0' */
190     if(len > 0) buff[0] = '\0';
191     return 0;
192   }
193   e = ip + il;
194   b = e - 1;
195   while(b >= ip) {
196     const char *term;
197     while(b >= ip && *b != '.') b--;  /* Rewind to previous part */
198     term = b + 1; /* term is one ahead, we went past it */
199     if(term != e) memcpy(o, term, e - term); /* no sense in copying nothing */
200     o += e - term; /* advance the term length */
201     e = b;
202     b = e - 1;
203     if(e >= ip) *o++ = '.'; /* we must be at . */
204   }
205   *o = '\0';
206   assert((o - buff) == il);
207   return o - buff;
208 }
209
210 static int dns_module_init(noit_module_t *self) {
211   const struct dns_nameval *nv;
212   struct dns_ctx *pctx;
213   int i;
214   pthread_mutex_init(&dns_ctx_store_lock, NULL);
215   pthread_mutex_init(&active_events_lock, NULL);
216   /* HASH the rr types */
217   for(i=0, nv = dns_type_index(i); nv->name; nv = dns_type_index(++i))
218     noit_hash_store(&dns_rtypes,
219                     nv->name, strlen(nv->name),
220                     (void *)nv);
221   /* HASH the class types */
222   for(i=0, nv = dns_class_index(i); nv->name; nv = dns_class_index(++i))
223     noit_hash_store(&dns_ctypes,
224                     nv->name, strlen(nv->name),
225                     (void *)nv);
226
227   noit_check_interpolate_register_oper_fn("inaddrarpa",
228                                           dns_interpolate_inaddr_arpa);
229
230   if (dns_init(NULL, 0) < 0 || (pctx = dns_new(NULL)) == NULL) {
231     noitL(nlerr, "Unable to initialize dns subsystem\n");
232     return -1;
233   }
234   dns_free(pctx);
235   if(dns_ctx_alloc(NULL) == NULL) {
236     noitL(nlerr, "Error setting up default dns resolver context.\n");
237     return -1;
238   }
239   return 0;
240 }
241
242 static void dns_check_cleanup(noit_module_t *self, noit_check_t *check) {
243 }
244
245 static int dns_eventer_callback(eventer_t e, int mask, void *closure,
246                                 struct timeval *now) {
247   dns_ctx_handle_t *h = closure;
248   dns_ioevent(h->ctx, now->tv_sec);
249   return EVENTER_READ | EVENTER_EXCEPTION;
250 }
251
252 static int dns_check_timeout(eventer_t e, int mask, void *closure,
253                              struct timeval *now) {
254   struct dns_check_info *ci;
255   ci = closure;
256   ci->timeout_event = NULL;
257   ci->check->flags &= ~NP_RUNNING;
258   dns_check_log_results(ci);
259   __deactivate_ci(ci);
260   return 0;
261 }
262
263 static int dns_invoke_timeouts(eventer_t e, int mask, void *closure,
264                                struct timeval *now) {
265   dns_ctx_handle_t *h = closure;
266   dns_timeouts(h->ctx, 0, now->tv_sec);
267   return 0;
268 }
269 static void eventer_dns_utm_fn(struct dns_ctx *ctx, int timeout, void *data) {
270   dns_ctx_handle_t *h = data;
271   eventer_t e = NULL, newe = NULL;
272   if(ctx == NULL) e = eventer_remove(h->timeout);
273   else {
274     assert(h->ctx == ctx);
275     if(timeout < 0) e = eventer_remove(h->timeout);
276     else {
277       newe = eventer_alloc();
278       newe->mask = EVENTER_TIMER;
279       newe->callback = dns_invoke_timeouts;
280       newe->closure = h;
281       gettimeofday(&newe->whence, NULL);
282       newe->whence.tv_sec += timeout;
283     }
284   }
285   if(e) eventer_free(e);
286   if(newe) eventer_add(newe);
287   h->timeout = newe;
288 }
289
290 static char *encode_txt(char *dst, const unsigned char *src, int len) {
291   int i;
292   for(i=0; i<len; i++) {
293     if(src[i] >= 127 || src[i] <= 31) {
294       snprintf(dst, 4, "\\%02x", src[i]);
295       dst += 3;
296     }
297     else if(src[i] == '\\') {
298       *dst++ = '\\';
299       *dst++ = '\\';
300     }
301     else {
302       *dst++ = (char)src[i];
303     }
304   }
305   *dst = '\0';
306   return dst;
307 }
308
309 static void decode_rr(struct dns_check_info *ci, struct dns_parse *p,
310                       struct dns_rr *rr, char **output) {
311   char buff[DNS_MAXDN], *txt_str, *c;
312   u_int32_t ttl, vu;
313   int32_t vs;
314   int totalsize;
315   const unsigned char *pkt = p->dnsp_pkt;
316   const unsigned char *end = p->dnsp_end;
317   const unsigned char *dptr = rr->dnsrr_dptr;
318   const unsigned char *dend = rr->dnsrr_dend;
319   unsigned char *dn = rr->dnsrr_dn;
320   const unsigned char *tmp;
321
322   /* Not interested unless it is the answer to my exact question */
323   if (!dns_dnequal(ci->dn, dn)) return;
324
325   if (!p->dnsp_rrl && !rr->dnsrr_dn[0] && rr->dnsrr_typ == DNS_T_OPT) {
326     /* We don't handle EDNS0 OPT records */
327     goto decode_err;
328   }
329   noitL(nldeb, "%s. %u %s %s\n", dns_dntosp(dn), rr->dnsrr_ttl,
330         dns_classname(rr->dnsrr_cls),
331         dns_typename(rr->dnsrr_typ));
332
333   ttl = rr->dnsrr_ttl;
334   noit_stats_set_metric(&ci->current, "ttl", METRIC_UINT32, &ttl);
335
336   switch(rr->dnsrr_typ) {
337    case DNS_T_A:
338     if (rr->dnsrr_dsz != 4) goto decode_err;
339     snprintf(buff, sizeof(buff), "%d.%d.%d.%d",
340              dptr[0], dptr[1], dptr[2], dptr[3]);
341     break;
342
343    case DNS_T_AAAA:
344     if (rr->dnsrr_dsz != 16) goto decode_err;
345     inet_ntop(AF_INET6, dptr, buff, 16);
346     break;
347
348    case DNS_T_TXT:
349     totalsize = 0;
350     for(tmp = dptr; tmp < dend; totalsize += *tmp, tmp += *tmp + 1)
351       if(tmp + *tmp + 1 > dend) goto decode_err;
352     /* worst case: every character escaped + '\0' */
353     txt_str = alloca(totalsize * 3 + 1);
354     if(!txt_str) goto decode_err;
355     c = txt_str;
356     for(tmp = dptr; tmp < dend; tmp += *tmp + 1)
357       c = encode_txt(c, tmp+1, *tmp);
358     break;
359
360    case DNS_T_MX:
361     snprintf(buff, sizeof(buff), "%d ", dns_get16(dptr));
362     tmp = dptr + 2;
363     if(dns_getdn(pkt, &tmp, end, dn, DNS_MAXDN) <= 0 || tmp != dend)
364       goto decode_err;
365     dns_dntop(dn, buff + strlen(buff), sizeof(buff) - strlen(buff));
366     break;
367
368    case DNS_T_SOA:
369      if(dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto decode_err;
370      dns_dntop(dn, buff, sizeof(buff));
371      noit_stats_set_metric(&ci->current, "name-server", METRIC_STRING, buff);
372      if(dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto decode_err;
373      dns_dntop(dn, buff, sizeof(buff));
374      noit_stats_set_metric(&ci->current, "email-addr", METRIC_STRING, buff);
375      if(dptr + 5 * sizeof(u_int32_t) != dend) goto decode_err;
376      vu = dns_get32(dptr); dptr += sizeof(u_int32_t);
377      noit_stats_set_metric(&ci->current, "serial", METRIC_UINT32, &vu);
378      /* the serial is what we elect to store as the "answer" as text...
379       * because it rarely changes and that seems the most interesting thing
380       * to track change-log-style.
381       */
382      snprintf(buff, sizeof(buff), "%u", vu);
383      vs = dns_get32(dptr); dptr += sizeof(int32_t);
384      noit_stats_set_metric(&ci->current, "refresh", METRIC_UINT32, &vs);
385      vs = dns_get32(dptr); dptr += sizeof(int32_t);
386      noit_stats_set_metric(&ci->current, "retry", METRIC_UINT32, &vs);
387      vs = dns_get32(dptr); dptr += sizeof(int32_t);
388      noit_stats_set_metric(&ci->current, "expiry", METRIC_UINT32, &vs);
389      vs = dns_get32(dptr); dptr += sizeof(int32_t);
390      noit_stats_set_metric(&ci->current, "minimum", METRIC_UINT32, &vs);
391      break;
392
393    case DNS_T_CNAME:
394    case DNS_T_PTR:
395    case DNS_T_NS:
396    case DNS_T_MB:
397    case DNS_T_MD:
398    case DNS_T_MF:
399    case DNS_T_MG:
400    case DNS_T_MR:
401     if(dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto decode_err;
402     dns_dntop(dn, buff, sizeof(buff));
403     break;
404
405    default:
406     break;
407   }
408   if(*output) {
409     int newlen = strlen(*output) + strlen(", ") + strlen(buff) + 1;
410     char *newstr;
411     newstr = malloc(newlen);
412     snprintf(newstr, newlen, "%s, %s", *output, buff);
413     free(*output);
414     *output = newstr;
415   }
416   else
417     *output = strdup(buff);
418   ci->nrr++;
419   return;
420
421  decode_err:
422   ci->error = strdup("RR decode error");
423   return;
424 }
425
426 static void dns_cb(struct dns_ctx *ctx, void *result, void *data) {
427   int r = dns_status(ctx);
428   struct dns_check_info *ci = data;
429   struct dns_parse p;
430   struct dns_rr rr;
431   unsigned nrr;
432   unsigned char dn[DNS_MAXDN];
433   const unsigned char *pkt, *cur, *end;
434   char *result_str = NULL;
435
436   /* If out ci isn't active, we must have timed out already */
437   if(!__isactive_ci(ci)) {
438     if(result) free(result);
439     return;
440   }
441
442   ci->timed_out = 0;
443   /* If we don't have a result, explode */
444   if (!result) {
445     ci->error = strdup(dns_strerror(r));
446     goto cleanup;
447   }
448
449   /* Process the packet */
450   pkt = result; end = pkt + r; cur = dns_payload(pkt);
451   dns_getdn(pkt, &cur, end, dn, sizeof(dn));
452   dns_initparse(&p, NULL, pkt, cur, end);
453   p.dnsp_qcls = p.dnsp_qtyp = 0;
454   nrr = 0;
455
456   while((r = dns_nextrr(&p, &rr)) > 0) {
457     if (!dns_dnequal(dn, rr.dnsrr_dn)) continue;
458     if ((ci->query_ctype == DNS_C_ANY || ci->query_ctype == rr.dnsrr_cls) &&
459         (ci->query_rtype == DNS_T_ANY || ci->query_rtype == rr.dnsrr_typ))
460       ++nrr;
461     else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) {
462       if (dns_getdn(pkt, &rr.dnsrr_dptr, end,
463                     p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 ||
464           rr.dnsrr_dptr != rr.dnsrr_dend) {
465         ci->error = strdup("protocol error");
466         break;
467       }
468       else {
469         noitL(nldeb, "%s.\n", dns_dntosp(dn));
470         noitL(nldeb, " CNAME %s.\n", dns_dntosp(p.dnsp_dnbuf));
471         dns_dntodn(p.dnsp_dnbuf, dn, sizeof(dn));
472         noitL(nldeb, " ---> '%s'\n", dn);
473       }
474     }
475   }
476   if (!r && !nrr) {
477     ci->error = strdup("no data");
478   }
479
480   dns_rewind(&p, NULL);
481   p.dnsp_qtyp = ci->query_rtype == DNS_T_ANY ? 0 : ci->query_rtype;
482   p.dnsp_qcls = ci->query_ctype == DNS_C_ANY ? 0 : ci->query_ctype;
483   while(dns_nextrr(&p, &rr))
484     decode_rr(ci, &p, &rr, &result_str);
485   noit_stats_set_metric(&ci->current, "answer", METRIC_STRING, result_str);
486
487  cleanup:
488   if(result) free(result);
489   if(ci->timeout_event) {
490     eventer_t e = eventer_remove(ci->timeout_event);
491     ci->timeout_event = NULL;
492     if(e) eventer_free(e);
493   }
494   ci->check->flags &= ~NP_RUNNING;
495   dns_check_log_results(ci);
496   __deactivate_ci(ci);
497 }
498
499 static int dns_check_send(noit_module_t *self, noit_check_t *check) {
500   struct dns_nameval *nv_pair;
501   eventer_t newe;
502   struct timeval p_int, now;
503   struct dns_check_info *ci = check->closure;
504   const char *config_val;
505   const char *rtype = NULL;
506   const char *nameserver = NULL;
507   const char *ctype = "IN";
508   const char *query = NULL;
509   char interpolated_nameserver[1024];
510   char interpolated_query[1024];
511   noit_hash_table check_attrs_hash = NOIT_HASH_EMPTY;
512
513   gettimeofday(&now, NULL);
514   memcpy(&check->last_fire_time, &now, sizeof(now));
515   ci->current.state = NP_BAD;
516   ci->current.available = NP_UNAVAILABLE;
517   ci->timed_out = 1;
518   ci->nrr = 0;
519
520   if(!strcmp(check->name, "in-addr.arpa")) {
521     /* in-addr.arpa defaults:
522      *   nameserver to NULL
523      *   rtype to PTR
524      *   query to %[:inaddrarpa:target].in-addr.arpa
525      */
526     nameserver = NULL;
527     rtype = "PTR";
528     query = "%[:inaddrarpa:target].in-addr.arpa";
529   }
530   else {
531     nameserver = "%[target]";
532     rtype = "A";
533     query = "%[name]";
534   }
535 #define CONFIG_OVERRIDE(a) \
536   if(noit_hash_retrieve(check->config, #a, strlen(#a), \
537                         (void **)&config_val) && \
538      strlen(config_val) > 0) \
539     a = config_val
540   CONFIG_OVERRIDE(ctype);
541   CONFIG_OVERRIDE(nameserver);
542   CONFIG_OVERRIDE(rtype);
543   CONFIG_OVERRIDE(query);
544
545   noit_check_make_attrs(check, &check_attrs_hash);
546 #define CA_STORE(a,b) noit_hash_store(&check_attrs_hash, a, strlen(a), b)
547   CA_STORE("target", check->target);
548   CA_STORE("name", check->name);
549   CA_STORE("module", check->module);
550
551   if(nameserver) {
552     noit_check_interpolate(interpolated_nameserver,
553                            sizeof(interpolated_nameserver),
554                            nameserver,
555                            &check_attrs_hash, check->config);
556     nameserver = interpolated_nameserver;
557   }
558   if(query) {
559     noit_check_interpolate(interpolated_query,
560                            sizeof(interpolated_query),
561                            query,
562                            &check_attrs_hash, check->config);
563     query = interpolated_query;
564   }
565   noit_hash_destroy(&check_attrs_hash, NULL, NULL);
566
567   check->flags |= NP_RUNNING;
568   noitL(nldeb, "dns_check_send(%p,%s,%s,%s,%s,%s)\n",
569         self, check->target, nameserver ? nameserver : "default",
570         query ? query : "null", ctype, rtype);
571
572   __activate_ci(ci);
573   /* If this ci has a handle and it isn't the one we need,
574    * we should release it
575    */
576   if(ci->h &&
577      ((ci->h->ns == NULL && nameserver != NULL) ||
578       (ci->h->ns != NULL && nameserver == NULL) ||
579       (ci->h->ns && strcmp(ci->h->ns, nameserver)))) {
580     dns_ctx_release(ci->h);
581     ci->h = NULL;
582   }
583   /* use the cached one, unless we don't have one */
584   if(!ci->h) ci->h = dns_ctx_alloc(nameserver);
585
586   /* Lookup out class */
587   if(!noit_hash_retrieve(&dns_ctypes, ctype, strlen(ctype),
588                          (void **)&nv_pair)) {
589     ci->error = strdup("bad class");
590   }
591   else
592     ci->query_ctype = nv_pair->val;
593
594   /* Lookup out rr type */
595   if(!noit_hash_retrieve(&dns_rtypes, rtype, strlen(rtype),
596                          (void **)&nv_pair)) {
597     ci->error = strdup("bad rr type");
598   }
599   else
600     ci->query_rtype = nv_pair->val;
601
602   if(!ci->error) {
603     /* Submit the query */
604     int abs;
605     if(!dns_ptodn(query, strlen(query), ci->dn, sizeof(ci->dn), &abs) ||
606        !dns_submit_dn(ci->h->ctx, ci->dn, ci->query_ctype, ci->query_rtype,
607                       abs | DNS_NOSRCH, NULL, dns_cb, ci)) {
608       ci->error = strdup("submission error");
609     }
610     else {
611       dns_timeouts(ci->h->ctx, -1, now.tv_sec);
612     }
613   }
614
615   /* we could have completed by now... if so, we've nothing to do */
616
617   if(!__isactive_ci(ci)) return 0;
618
619   if(ci->error) {
620     /* Errors here are easy, fail and avoid scheduling a timeout */
621     ci->check->flags &= ~NP_RUNNING;
622     dns_check_log_results(ci);
623     __deactivate_ci(ci);
624     return 0;
625   }
626
627   newe = eventer_alloc();
628   newe->mask = EVENTER_TIMER;
629   gettimeofday(&now, NULL);
630   p_int.tv_sec = check->timeout / 1000;
631   p_int.tv_usec = (check->timeout % 1000) * 1000;
632   add_timeval(now, p_int, &newe->whence);
633   newe->closure = ci;
634   newe->callback = dns_check_timeout;
635   ci->timeout_event = newe;
636   eventer_add(newe);
637
638   return 0;
639 }
640
641 static int dns_initiate_check(noit_module_t *self, noit_check_t *check,
642                               int once, noit_check_t *cause) {
643   struct dns_check_info *ci;
644   if(!check->closure)
645     check->closure = calloc(1, sizeof(struct dns_check_info));
646   ci = check->closure;
647   ci->check = check;
648   ci->self = self;
649   INITIATE_CHECK(dns_check_send, self, check);
650   return 0;
651 }
652
653 static int dns_config(noit_module_t *self, noit_hash_table *options) {
654   return 0;
655 }
656
657 static int dns_onload(noit_image_t *self) {
658   nlerr = noit_log_stream_find("error/dns");
659   nldeb = noit_log_stream_find("debug/dns");
660   if(!nlerr) nlerr = noit_stderr;
661   if(!nldeb) nldeb = noit_debug;
662   eventer_name_callback("dns/dns_eventer_callback", dns_eventer_callback);
663   eventer_name_callback("dns/dns_check_timeout", dns_check_timeout);
664   eventer_name_callback("dns/dns_invoke_timeouts", dns_invoke_timeouts);
665   return 0;
666 }
667
668 noit_module_t dns = {
669   {
670     NOIT_MODULE_MAGIC,
671     NOIT_MODULE_ABI_VERSION,
672     "dns",
673     "DNS RR checker",
674     dns_onload
675   },
676   dns_config,
677   dns_module_init,
678   dns_initiate_check,
679   dns_check_cleanup
680 };
681
Note: See TracBrowser for help on using the browser.