root/src/modules/dns.c

Revision 6210da7ee0e2ed143d71a8e00b709f16e71059f8, 20.0 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

various changes to avoid dereferencing type-punned pointers and breaking strict-aliasing rules, refs #34

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