root/src/noit_check_resolver.c

Revision 7a90ad9a967682c691486d6ff5617687a0a2b8c8, 18.2 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 months ago)

simplify this and do it the same way on all platforms

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2011, 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 <stdlib.h>
37 #include <unistd.h>
38 #include <time.h>
39 #include <ctype.h>
40 #include <assert.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <netdb.h>
44
45 #include "eventer/eventer.h"
46 #include "utils/noit_log.h"
47 #include "utils/noit_skiplist.h"
48 #include "utils/noit_hash.h"
49 #include "udns/udns.h"
50 #include "noit_console.h"
51
52 #define MAX_RR 256
53 #define DEFAULT_FAILED_TTL 60
54 #define DEFAULT_PURGE_AGE  1200 /* 20 minutes */
55
56 static struct dns_ctx *dns_ctx;
57 static noit_skiplist nc_dns_cache;
58 static eventer_t dns_cache_timeout = NULL;
59 static noit_hash_table etc_hosts_cache;
60
61 typedef struct {
62   time_t last_needed;
63   time_t last_updated;
64   noit_boolean lookup_inflight_v4;
65   noit_boolean lookup_inflight_v6;
66   char *target;
67   unsigned char dn[DNS_MAXDN];
68   time_t ttl;
69   int ip4_cnt;
70   char **ip4;
71   int ip6_cnt;
72   char **ip6;
73 } dns_cache_node;
74
75 typedef struct {
76   char *target;
77   struct in_addr ip4;
78   struct in6_addr ip6;
79   int has_ip4:1;
80   int has_ip6:1;
81 } static_host_node;
82
83 void dns_cache_node_free(void *vn) {
84   dns_cache_node *n = vn;
85   int i;
86   if(!n) return;
87   if(n->target) free(n->target);
88   for(i=0;i<n->ip4_cnt;i++) if(n->ip4[i]) free(n->ip4[i]);
89   for(i=0;i<n->ip6_cnt;i++) if(n->ip6[i]) free(n->ip6[i]);
90   if(n->ip4) free(n->ip4);
91   if(n->ip6) free(n->ip6);
92   free(n);
93 }
94
95 static int name_lookup(const void *av, const void *bv) {
96   const dns_cache_node *a = av;
97   const dns_cache_node *b = bv;
98   return strcmp(a->target, b->target);
99 }
100 static int name_lookup_k(const void *akv, const void *bv) {
101   const char *ak = akv;
102   const dns_cache_node *b = bv;
103   return strcmp(ak, b->target);
104 }
105 static int refresh_idx(const void *av, const void *bv) {
106   const dns_cache_node *a = av;
107   const dns_cache_node *b = bv;
108   if((a->last_updated + a->ttl) < (b->last_updated + b->ttl)) return -1;
109   return 1;
110 }
111 static int refresh_idx_k(const void *akv, const void *bv) {
112   time_t f = (time_t) akv;
113   const dns_cache_node *b = bv;
114   if(f < (b->last_updated + b->ttl)) return -1;
115   return 1;
116 }
117
118 void noit_check_resolver_remind(const char *target) {
119   dns_cache_node *n;
120   if(!target) return;
121   n = noit_skiplist_find(&nc_dns_cache, target, NULL);
122   if(n != NULL) {
123     n->last_needed = time(NULL);
124     return;
125   }
126   n = calloc(1, sizeof(*n));
127   n->target = strdup(target);
128   n->last_needed = time(NULL);
129   noit_skiplist_insert(&nc_dns_cache, n);
130 }
131
132
133 int noit_check_resolver_fetch(const char *target, char *buff, int len,
134                               uint8_t prefer_family) {
135   int i;
136   uint8_t progression[2];
137   dns_cache_node *n;
138   void *vnode;
139
140   buff[0] = '\0';
141   if(!target) return -1;
142   progression[0] = prefer_family;
143   progression[1] = (prefer_family == AF_INET) ? AF_INET6 : AF_INET;
144
145   if(noit_hash_retrieve(&etc_hosts_cache, target, strlen(target), &vnode)) {
146     static_host_node *node = vnode;
147     for(i=0; i<2; i++) {
148       switch(progression[i]) {
149         case AF_INET:
150           if(node->has_ip4) {
151             inet_ntop(AF_INET, &node->ip4, buff, len);
152             return 1;
153           }
154           break;
155         case AF_INET6:
156           if(node->has_ip6) {
157             inet_ntop(AF_INET6, &node->ip6, buff, len);
158             return 1;
159           }
160           break;
161       }
162     }
163   }
164
165   n = noit_skiplist_find(&nc_dns_cache, target, NULL);
166   if(n != NULL) {
167     int rv;
168     if(n->last_updated == 0) return -1; /* not resolved yet */
169     rv = n->ip4_cnt + n->ip6_cnt;
170     for(i=0; i<2; i++) {
171       switch(progression[i]) {
172         case AF_INET:
173           if(n->ip4_cnt > 0) {
174             strlcpy(buff, n->ip4[0], len);
175             return rv;
176           }
177           break;
178         case AF_INET6:
179           if(n->ip6_cnt > 0) {
180             strlcpy(buff, n->ip6[0], len);
181             return rv;
182           }
183           break;
184       }
185     }
186     return rv;
187   }
188   return -1;
189 }
190
191 static void blank_update_v4(dns_cache_node *n) {
192   int i;
193   for(i=0;i<n->ip4_cnt;i++) if(n->ip4[i]) free(n->ip4[i]);
194   if(n->ip4) free(n->ip4);
195   n->ip4 = NULL;
196   n->ip4_cnt = 0;
197   noit_skiplist_remove(&nc_dns_cache, n->target, NULL);
198   n->last_updated = time(NULL);
199   n->ttl = DEFAULT_FAILED_TTL;
200   n->lookup_inflight_v4 = noit_false;
201   noit_skiplist_insert(&nc_dns_cache, n);
202 }
203 static void blank_update_v6(dns_cache_node *n) {
204   int i;
205   for(i=0;i<n->ip6_cnt;i++) if(n->ip6[i]) free(n->ip6[i]);
206   if(n->ip6) free(n->ip6);
207   n->ip6 = NULL;
208   n->ip6_cnt = 0;
209   noit_skiplist_remove(&nc_dns_cache, n->target, NULL);
210   n->last_updated = time(NULL);
211   n->ttl = DEFAULT_FAILED_TTL;
212   n->lookup_inflight_v6 = noit_false;
213   noit_skiplist_insert(&nc_dns_cache, n);
214 }
215 static void blank_update(dns_cache_node *n) {
216   blank_update_v4(n);
217   blank_update_v6(n);
218 }
219
220 static int dns_cache_callback(eventer_t e, int mask, void *closure,
221                               struct timeval *now) {
222   struct dns_ctx *ctx = closure;
223   dns_ioevent(ctx, now->tv_sec);
224   return EVENTER_READ | EVENTER_EXCEPTION;
225 }
226
227 static int dns_invoke_timeouts(eventer_t e, int mask, void *closure,
228                                struct timeval *now) {
229   struct dns_ctx *ctx = closure;
230   dns_timeouts(ctx, 0, now->tv_sec);
231   return 0;
232 }
233
234 static void dns_cache_utm_fn(struct dns_ctx *ctx, int timeout, void *data) {
235   eventer_t e = NULL, newe = NULL;
236   if(ctx == NULL) e = eventer_remove(dns_cache_timeout);
237   else {
238     if(timeout < 0) e = eventer_remove(dns_cache_timeout);
239     else {
240       newe = eventer_alloc();
241       newe->mask = EVENTER_TIMER;
242       newe->callback = dns_invoke_timeouts;
243       newe->closure = dns_ctx;
244       gettimeofday(&newe->whence, NULL);
245       newe->whence.tv_sec += timeout;
246     }
247   }
248   if(e) eventer_free(e);
249   if(newe) eventer_add(newe);
250   dns_cache_timeout = newe;
251 }
252
253 static void dns_cache_resolve(struct dns_ctx *ctx, void *result, void *data,
254                               enum dns_type rtype) {
255   int i, ttl, acnt, r = dns_status(ctx);
256   dns_cache_node *n = data;
257   unsigned char idn[DNS_MAXDN], dn[DNS_MAXDN];
258   struct dns_parse p;
259   struct dns_rr rr;
260   unsigned nrr;
261   char **answers;
262   const unsigned char *pkt, *cur, *end;
263
264   if(!result) goto blank;
265
266   dns_dntodn(n->dn, idn, sizeof(idn));
267
268   pkt = result; end = pkt + r; cur = dns_payload(pkt);
269   dns_getdn(pkt, &cur, end, dn, sizeof(dn));
270   dns_initparse(&p, NULL, pkt, cur, end);
271   p.dnsp_qcls = 0;
272   p.dnsp_qtyp = 0;
273   nrr = 0;
274   ttl = 0;
275
276   while((r = dns_nextrr(&p, &rr)) > 0) {
277     if (!dns_dnequal(idn, rr.dnsrr_dn)) continue;
278     if (DNS_C_IN == rr.dnsrr_cls && rtype == rr.dnsrr_typ) ++nrr;
279     else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) {
280       if (dns_getdn(pkt, &rr.dnsrr_dptr, end,
281                     p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 ||
282           rr.dnsrr_dptr != rr.dnsrr_dend) {
283         break;
284       }
285       else {
286         if(rr.dnsrr_ttl > 0 && (ttl == 0 || rr.dnsrr_ttl < ttl))
287           ttl = rr.dnsrr_ttl;
288         dns_dntodn(p.dnsp_dnbuf, idn, sizeof(idn));
289       }
290     }
291   }
292   if(!r && !nrr) goto blank;
293
294   dns_rewind(&p, NULL);
295   p.dnsp_qcls = DNS_C_IN;
296   p.dnsp_qtyp = rtype;
297   answers = calloc(nrr, sizeof(*answers));
298   acnt = 0;
299   while(dns_nextrr(&p, &rr) && nrr < MAX_RR) {
300     char buff[INET6_ADDRSTRLEN];
301     if (!dns_dnequal(idn, rr.dnsrr_dn)) continue;
302     if (p.dnsp_rrl && !rr.dnsrr_dn[0] && rr.dnsrr_typ == DNS_T_OPT) continue;
303     if (rtype == rr.dnsrr_typ) {
304       if(rr.dnsrr_ttl > 0 && (ttl == 0 || rr.dnsrr_ttl < ttl))
305         ttl = rr.dnsrr_ttl;
306       switch(rr.dnsrr_typ) {
307         case DNS_T_A:
308           if(rr.dnsrr_dsz != 4) continue;
309           inet_ntop(AF_INET, rr.dnsrr_dptr, buff, sizeof(buff));
310           answers[acnt++] = strdup(buff);
311           break;
312         case DNS_T_AAAA:
313           if(rr.dnsrr_dsz != 16) continue;
314           inet_ntop(AF_INET6, rr.dnsrr_dptr, buff, sizeof(buff));
315           answers[acnt++] = strdup(buff);
316           break;
317         default:
318           break;
319       }
320     }
321   }
322
323   n->ttl = ttl;
324   if(rtype == DNS_T_A) {
325     for(i=0;i<n->ip4_cnt;i++) if(n->ip4[i]) free(n->ip4[i]);
326     if(n->ip4) free(n->ip4);
327     n->ip4_cnt = acnt;
328     n->ip4 = answers;
329     n->lookup_inflight_v4 = noit_false;
330   }
331   else if(rtype == DNS_T_AAAA) {
332     for(i=0;i<n->ip6_cnt;i++) if(n->ip6[i]) free(n->ip6[i]);
333     if(n->ip6) free(n->ip6);
334     n->ip6_cnt = acnt;
335     n->ip6 = answers;
336     n->lookup_inflight_v6 = noit_false;
337   }
338   else {
339     if(answers) free(answers);
340     if(result) free(result);
341      return;
342   }
343   noit_skiplist_remove(&nc_dns_cache, n->target, NULL);
344   n->last_updated = time(NULL);
345   noit_skiplist_insert(&nc_dns_cache, n);
346   noitL(noit_debug, "Resolved %s/%s -> %d records\n", n->target,
347         (rtype == DNS_T_AAAA ? "IPv6" : (rtype == DNS_T_A ? "IPv4" : "???")),
348         acnt);
349   if(result) free(result);
350   return;
351
352  blank:
353   if(rtype == DNS_T_A) blank_update_v4(n);
354   if(rtype == DNS_T_AAAA) blank_update_v6(n);
355   noitL(noit_debug, "Resolved %s/%s -> blank\n", n->target,
356         (rtype == DNS_T_AAAA ? "IPv6" : (rtype == DNS_T_A ? "IPv4" : "???")));
357   if(result) free(result);
358   return;
359 }
360 static void dns_cache_resolve_v4(struct dns_ctx *ctx, void *result, void *data) {
361   dns_cache_resolve(ctx, result, data, DNS_T_A);
362 }
363 static void dns_cache_resolve_v6(struct dns_ctx *ctx, void *result, void *data) {
364   dns_cache_resolve(ctx, result, data, DNS_T_AAAA);
365 }
366
367 void noit_check_resolver_maintain() {
368   time_t now;
369   noit_skiplist *tlist;
370   noit_skiplist_node *sn;
371
372   now = time(NULL);
373   sn = noit_skiplist_getlist(nc_dns_cache.index);
374   assert(sn);
375   tlist = sn->data;
376   assert(tlist);
377   sn = noit_skiplist_getlist(tlist);
378   while(sn) {
379     dns_cache_node *n = sn->data;
380     noit_skiplist_next(tlist, &sn); /* move forward */
381     /* remove if needed */
382     if(n->last_updated + n->ttl > now) break;
383     if(n->last_needed + DEFAULT_PURGE_AGE < now &&
384        !(n->lookup_inflight_v4 || n->lookup_inflight_v6))
385       noit_skiplist_remove(&nc_dns_cache, n->target, dns_cache_node_free);
386     else {
387       int abs;
388       if(!dns_ptodn(n->target, strlen(n->target),
389                     n->dn, sizeof(n->dn), &abs)) {
390         blank_update(n);
391       }
392       else {
393         if(!n->lookup_inflight_v4) {
394           n->lookup_inflight_v4 = noit_true;
395           if(!dns_submit_dn(dns_ctx, n->dn, DNS_C_IN, DNS_T_A,
396                             abs | DNS_NOSRCH, NULL, dns_cache_resolve_v4, n))
397             blank_update_v4(n);
398           else
399             dns_timeouts(dns_ctx, -1, now);
400         }
401         if(!n->lookup_inflight_v6) {
402           n->lookup_inflight_v6 = noit_true;
403           if(!dns_submit_dn(dns_ctx, n->dn, DNS_C_IN, DNS_T_AAAA,
404                             abs | DNS_NOSRCH, NULL, dns_cache_resolve_v6, n))
405             blank_update_v6(n);
406           else
407             dns_timeouts(dns_ctx, -1, now);
408         }
409       }
410       noitL(noit_debug, "Firing lookup for '%s'\n", n->target);
411       continue;
412     }
413   }
414 }
415
416 int noit_check_resolver_loop(eventer_t e, int mask, void *c,
417                              struct timeval *now) {
418   noit_check_resolver_maintain();
419   eventer_add_in_s_us(noit_check_resolver_loop, NULL, 1, 0);
420   return 0;
421 }
422
423 static int
424 nc_print_dns_cache_node(noit_console_closure_t ncct,
425                         const char *target, dns_cache_node *n) {
426   nc_printf(ncct, "==== %s ====\n", target);
427   if(!n) nc_printf(ncct, "NOT FOUND\n");
428   else {
429     int i;
430     time_t now = time(NULL);
431     nc_printf(ncct, "%16s: %ds ago\n", "last needed", now - n->last_needed);
432     nc_printf(ncct, "%16s: %ds ago\n", "resolved", now - n->last_updated);
433     nc_printf(ncct, "%16s: %ds\n", "ttl", n->ttl);
434     if(n->lookup_inflight_v4) nc_printf(ncct, "actively resolving A RRs\n");
435     if(n->lookup_inflight_v6) nc_printf(ncct, "actively resolving AAAA RRs\n");
436     for(i=0;i<n->ip4_cnt;i++)
437       nc_printf(ncct, "%17s %s\n", i?"":"IPv4:", n->ip4[i]);
438     for(i=0;i<n->ip6_cnt;i++)
439       nc_printf(ncct, "%17s %s\n", i?"":"IPv6:", n->ip6[i]);
440   }
441   return 0;
442 }
443 static int
444 noit_console_show_dns_cache(noit_console_closure_t ncct,
445                             int argc, char **argv,
446                             noit_console_state_t *dstate,
447                             void *closure) {
448   int i;
449
450   if(argc == 0) {
451     noit_skiplist_node *sn;
452     for(sn = noit_skiplist_getlist(&nc_dns_cache); sn;
453         noit_skiplist_next(&nc_dns_cache, &sn)) {
454       dns_cache_node *n = (dns_cache_node *)sn->data;
455       nc_print_dns_cache_node(ncct, n->target, n);
456     }
457   }
458   for(i=0;i<argc;i++) {
459     dns_cache_node *n;
460     n = noit_skiplist_find(&nc_dns_cache, argv[i], NULL);
461     nc_print_dns_cache_node(ncct, argv[i], n);
462   }
463   return 0;
464 }
465 static int
466 noit_console_manip_dns_cache(noit_console_closure_t ncct,
467                              int argc, char **argv,
468                              noit_console_state_t *dstate,
469                              void *closure) {
470   int i;
471   if(argc == 0) {
472     nc_printf(ncct, "dns_cache what?\n");
473     return 0;
474   }
475   if(closure == NULL) {
476     /* adding */
477     for(i=0;i<argc;i++) {
478       dns_cache_node *n;
479       if(NULL != (n = noit_skiplist_find(&nc_dns_cache, argv[i], NULL))) {
480         nc_printf(ncct, " == Already in system ==\n");
481         nc_print_dns_cache_node(ncct, argv[i], n);
482       }
483       else {
484         nc_printf(ncct, "%s submitted.\n", argv[i]);
485         noit_check_resolver_remind(argv[i]);
486       }
487     }
488   }
489   else {
490     for(i=0;i<argc;i++) {
491       dns_cache_node *n;
492       if(NULL != (n = noit_skiplist_find(&nc_dns_cache, argv[i], NULL))) {
493         if(n->lookup_inflight_v4 || n->lookup_inflight_v6)
494           nc_printf(ncct, "%s is currently resolving and cannot be removed.\n");
495         else {
496           noit_skiplist_remove(&nc_dns_cache, argv[i], dns_cache_node_free);
497           nc_printf(ncct, "%s removed.\n", argv[i]);
498         }
499       }
500       else nc_printf(ncct, "%s not in system.\n", argv[i]);
501     }
502   }
503   return 0;
504 }
505
506 static void
507 register_console_dns_cache_commands() {
508   noit_console_state_t *tl;
509   cmd_info_t *showcmd, *nocmd;
510
511   tl = noit_console_state_initial();
512   showcmd = noit_console_state_get_cmd(tl, "show");
513   assert(showcmd && showcmd->dstate);
514
515   nocmd = noit_console_state_get_cmd(tl, "no");
516   assert(nocmd && nocmd->dstate);
517
518   noit_console_state_add_cmd(showcmd->dstate,
519     NCSCMD("dns_cache", noit_console_show_dns_cache, NULL, NULL, NULL));
520
521   noit_console_state_add_cmd(tl,
522     NCSCMD("dns_cache", noit_console_manip_dns_cache, NULL, NULL, NULL));
523
524   noit_console_state_add_cmd(nocmd->dstate,
525     NCSCMD("dns_cache", noit_console_manip_dns_cache, NULL, NULL, (void *)0x1));
526 }
527
528 int
529 noit_check_etc_hosts_cache_refresh(eventer_t e, int mask, void *closure,
530                                    struct timeval *now) {
531   static struct stat last_stat;
532   struct stat sb;
533   struct hostent *ent;
534   int reload = 0;
535
536   memset(&sb, 0, sizeof(sb));
537   stat("/etc/hosts", &sb);
538 #define CSTAT(f) (sb.f == last_stat.f)
539   reload = ! (CSTAT(st_dev) && CSTAT(st_ino) && CSTAT(st_mode) && CSTAT(st_uid) &&
540               CSTAT(st_gid) && CSTAT(st_size) && CSTAT(st_mtime));
541   memcpy(&last_stat, &sb, sizeof(sb));
542
543   if(reload) {
544     noit_hash_delete_all(&etc_hosts_cache, free, free);
545     while(NULL != (ent = gethostent())) {
546       int i = 0;
547       char *name = ent->h_name;
548       while(name) {
549         void *vnode;
550         static_host_node *node;
551         if(!noit_hash_retrieve(&etc_hosts_cache, name, strlen(name), &vnode)) {
552           vnode = node = calloc(1, sizeof(*node));
553           node->target = strdup(name);
554           noit_hash_store(&etc_hosts_cache, node->target, strlen(node->target), node);
555         }
556         node = vnode;
557  
558         if(ent->h_addrtype == AF_INET) {
559           node->has_ip4 = 1;
560           memcpy(&node->ip4, ent->h_addr_list[0], ent->h_length);
561         }
562         if(ent->h_addrtype == AF_INET6) {
563           node->has_ip6 = 1;
564           memcpy(&node->ip6, ent->h_addr_list[0], ent->h_length);
565         }
566        
567         name = ent->h_aliases[i++];
568       }
569     }
570     endhostent();
571     noitL(noit_error, "reloaded %d /etc/hosts targets\n", etc_hosts_cache.size);
572   }
573
574   eventer_add_in_s_us(noit_check_etc_hosts_cache_refresh, NULL, 1, 0);
575   return 0;
576 }
577
578 void noit_check_resolver_init() {
579   eventer_t e;
580   if(dns_init(NULL, 0) < 0)
581     noitL(noit_error, "dns initialization failed.\n");
582   dns_ctx = dns_new(NULL);
583   if(dns_init(dns_ctx, 0) != 0 ||
584      dns_open(dns_ctx) < 0) {
585     noitL(noit_error, "dns initialization failed.\n");
586   }
587   eventer_name_callback("dns_cache_callback", dns_cache_callback);
588   dns_set_tmcbck(dns_ctx, dns_cache_utm_fn, dns_ctx);
589   e = eventer_alloc();
590   e->mask = EVENTER_READ | EVENTER_EXCEPTION;
591   e->closure = dns_ctx;
592   e->callback = dns_cache_callback;
593   e->fd = dns_sock(dns_ctx);
594   eventer_add(e);
595
596   noit_skiplist_init(&nc_dns_cache);
597   noit_skiplist_set_compare(&nc_dns_cache, name_lookup, name_lookup_k);
598   noit_skiplist_add_index(&nc_dns_cache, refresh_idx, refresh_idx_k);
599   noit_check_resolver_loop(NULL, 0, NULL, NULL);
600   register_console_dns_cache_commands();
601
602   noit_hash_init(&etc_hosts_cache);
603   noit_check_etc_hosts_cache_refresh(NULL, 0, NULL, NULL);
604 }
Note: See TracBrowser for help on using the browser.