root/src/modules/dns.c

Revision afe029db8189f6fd97a26397f1661bc9b3b3cabb, 21.7 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 7 years ago)

this is unused

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