1 /*
2 * PgBouncer - Lightweight connection pooler for PostgreSQL.
3 *
4 * Copyright (c) 2007-2010 Marko Kreen, Skype Technologies OÜ
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include "bouncer.h"
20
21 #include <usual/netdb.h>
22
23 #if !defined(USE_EVDNS) && !defined(USE_UDNS) && !defined(USE_CARES)
24 #define USE_GETADDRINFO_A
25 #endif
26
27 #ifdef USE_EVDNS
28 #include <event2/dns.h>
29 #define addrinfo evutil_addrinfo
30 #define freeaddrinfo evutil_freeaddrinfo
31 #endif /* USE_EVDNS */
32
33 #ifdef USE_CARES
34 #include <ares.h>
35 #include <ares_dns.h>
36 #ifndef WIN32
37 #include <arpa/nameser.h>
38 #else
39 #include <nameser.h>
40 #endif
41 #define ZONE_RECHECK 1
42 #else
43 /* only c-ares requires this */
44 #define impl_per_loop(ctx)
45 #endif
46
47 #ifdef USE_UDNS
48 #include <udns.h>
49 #define ZONE_RECHECK 1
50 #endif
51
52 #ifndef ZONE_RECHECK
53 #define ZONE_RECHECK 0
54 /* no implementation, also avoid 'unused' warning */
55 #define impl_query_soa_serial(ctx, name) do { if (0) got_zone_serial(ctx, NULL); } while (0)
56 #define cf_dns_zone_check_period (0)
57 #endif
58
59 /*
60 * There can be several client request (tokens)
61 * attached to single actual request.
62 */
63 struct DNSToken {
64 struct List node;
65 adns_callback_f cb_func;
66 void *cb_arg;
67 };
68
69 /*
70 * Cached DNS query (hostname).
71 */
72 struct DNSRequest {
73 struct AANode node; /* DNSContext->req_tree */
74 struct List znode; /* DNSZone->host_list */
75
76 struct DNSContext *ctx;
77 struct DNSZone *zone;
78
79 struct List ucb_list; /* DNSToken->node */
80
81 char *name;
82 int namelen;
83
84 bool done;
85
86 struct addrinfo *result;
87 struct addrinfo *current;
88 struct addrinfo *oldres;
89
90 usec_t res_ttl;
91 };
92
93 /* zone name serial */
94 struct DNSZone {
95 struct List lnode; /* DNSContext->zone_list */
96 struct AANode tnode; /* DNSContext->zone_tree */
97
98 struct StatList host_list; /* DNSRequest->znode */
99
100 char *zonename;
101 uint32_t serial;
102 };
103
104 /*
105 * Top struct for DNS data.
106 */
107 struct DNSContext {
108 struct AATree req_tree;
109 void *edns;
110
111 struct AATree zone_tree; /* DNSZone->tnode */
112 struct List zone_list; /* DNSZone->lnode */
113
114 struct DNSZone *cur_zone;
115 struct event ev_zone_timer;
116 int zone_state;
117
118 int active; /* number of in-flight queries */
119 };
120
121 static void deliver_info(struct DNSRequest *req);
122 static void got_result_gai(int result, struct addrinfo *res, void *arg);
123
124 static void zone_register(struct DNSContext *ctx, struct DNSRequest *req);
125 static void zone_init(struct DNSContext *ctx);
126 static void zone_free(struct DNSContext *ctx);
127
128 static void got_zone_serial(struct DNSContext *ctx, uint32_t *serial);
129
130 /*
131 * Custom addrinfo generation
132 */
133
134 #if defined(USE_UDNS) || defined(USE_CARES)
135
mk_addrinfo(const void * adr,int af)136 static struct addrinfo *mk_addrinfo(const void *adr, int af)
137 {
138 struct addrinfo *ai;
139
140 ai = calloc(1, sizeof(*ai));
141 if (!ai)
142 return NULL;
143
144 if (af == AF_INET) {
145 struct sockaddr_in *sa4;
146 sa4 = calloc(1, sizeof(*sa4));
147 if (!sa4)
148 goto failed;
149 memcpy(&sa4->sin_addr, adr, 4);
150 sa4->sin_family = af;
151 ai->ai_addr = (struct sockaddr *)sa4;
152 ai->ai_addrlen = sizeof(*sa4);
153 } else if (af == AF_INET6) {
154 struct sockaddr_in6 *sa6;
155 sa6 = calloc(1, sizeof(*sa6));
156 if (!sa6)
157 goto failed;
158 memcpy(&sa6->sin6_addr, adr, sizeof(sa6->sin6_addr));
159 sa6->sin6_family = af;
160 ai->ai_addr = (struct sockaddr *)sa6;
161 ai->ai_addrlen = sizeof(*sa6);
162 }
163 ai->ai_protocol = IPPROTO_TCP;
164 ai->ai_socktype = SOCK_STREAM;
165 ai->ai_family = af;
166 return ai;
167 failed:
168 free(ai);
169 return NULL;
170 }
171
172 #define freeaddrinfo(x) local_freeaddrinfo(x)
173
freeaddrinfo(struct addrinfo * ai)174 static void freeaddrinfo(struct addrinfo *ai)
175 {
176 struct addrinfo *cur;
177 while (ai) {
178 cur = ai;
179 ai = ai->ai_next;
180 free(cur->ai_addr);
181 free(cur);
182 }
183 }
184
185 #if defined(USE_UDNS)
186
convert_ipv4_result(const struct in_addr * adrs,int count)187 static inline struct addrinfo *convert_ipv4_result(const struct in_addr *adrs, int count)
188 {
189 struct addrinfo *ai, *first = NULL, *last = NULL;
190 int i;
191
192 for (i = 0; i < count; i++) {
193 ai = mk_addrinfo(&adrs[i], AF_INET);
194 if (!ai)
195 goto failed;
196
197 if (!first)
198 first = ai;
199 else
200 last->ai_next = ai;
201 last = ai;
202 }
203 return first;
204 failed:
205 freeaddrinfo(first);
206 return NULL;
207 }
208
209 #endif /* USE_UDNS */
210
211 #ifdef USE_CARES
212
convert_hostent(const struct hostent * h)213 static inline struct addrinfo *convert_hostent(const struct hostent *h)
214 {
215 struct addrinfo *ai, *first = NULL, *last = NULL;
216 int i;
217
218 for (i = 0; h->h_addr_list[i]; i++) {
219 ai = mk_addrinfo(h->h_addr_list[i], h->h_addrtype);
220 if (!ai)
221 goto failed;
222
223 if (!first)
224 first = ai;
225 else
226 last->ai_next = ai;
227 last = ai;
228 }
229 return first;
230 failed:
231 freeaddrinfo(first);
232 return NULL;
233 }
234
235 #endif /* USE_CARES */
236
237 #endif /* custom addrinfo */
238
239
240 /*
241 * ADNS with glibc's getaddrinfo_a()
242 */
243
244 #ifdef USE_GETADDRINFO_A
245
adns_get_backend(void)246 const char *adns_get_backend(void)
247 {
248 #ifdef HAVE_GETADDRINFO_A
249 return "libc"
250 #ifdef __GLIBC__
251 "-" STR(__GLIBC__) "." STR(__GLIBC_MINOR__);
252 #endif
253 ;
254 #else
255 return "compat";
256 #endif
257 }
258
259 struct GaiRequest {
260 struct List node;
261 struct DNSRequest *req;
262 struct gaicb gairq;
263 };
264
265 struct GaiContext {
266 struct DNSContext *ctx;
267 struct List gairq_list;
268 struct event ev;
269 struct sigevent sev;
270 };
271
dns_signal(int f,short ev,void * arg)272 static void dns_signal(int f, short ev, void *arg)
273 {
274 struct GaiContext *gctx = arg;
275 struct List *el, *tmp;
276 struct GaiRequest *rq;
277 int e;
278 list_for_each_safe(el, &gctx->gairq_list, tmp) {
279 rq = container_of(el, struct GaiRequest, node);
280 e = gai_error(&rq->gairq);
281 if (e == EAI_INPROGRESS)
282 continue;
283
284 /* got one */
285 list_del(&rq->node);
286 got_result_gai(e, rq->gairq.ar_result, rq->req);
287 free(rq);
288 }
289 }
290
impl_init(struct DNSContext * ctx)291 static bool impl_init(struct DNSContext *ctx)
292 {
293 struct GaiContext *gctx;
294
295 if (cf_resolv_conf && cf_resolv_conf[0]) {
296 log_error("resolv_conf setting is not supported by libc adns");
297 return false;
298 }
299
300 gctx = calloc(1, sizeof(*gctx));
301 if (!gctx)
302 return false;
303 list_init(&gctx->gairq_list);
304 gctx->ctx = ctx;
305
306 gctx->sev.sigev_notify = SIGEV_SIGNAL;
307 gctx->sev.sigev_signo = SIGALRM;
308
309 evsignal_assign(&gctx->ev, pgb_event_base, SIGALRM, dns_signal, gctx);
310 if (evsignal_add(&gctx->ev, NULL) < 0) {
311 free(gctx);
312 return false;
313 }
314 ctx->edns = gctx;
315 return true;
316 }
317
impl_launch_query(struct DNSRequest * req)318 static void impl_launch_query(struct DNSRequest *req)
319 {
320 static const struct addrinfo hints = { .ai_socktype = SOCK_STREAM };
321
322 struct GaiContext *gctx = req->ctx->edns;
323 struct GaiRequest *grq;
324 int res;
325 struct gaicb *cb;
326
327 grq = calloc(1, sizeof(*grq));
328 if (!grq)
329 goto failed2;
330
331 list_init(&grq->node);
332 grq->req = req;
333 grq->gairq.ar_name = req->name;
334 grq->gairq.ar_request = &hints;
335 list_append(&gctx->gairq_list, &grq->node);
336
337 cb = &grq->gairq;
338 res = getaddrinfo_a(GAI_NOWAIT, &cb, 1, &gctx->sev);
339 if (res != 0)
340 goto failed;
341 return;
342
343 failed:
344 if (res == EAI_SYSTEM) {
345 log_warning("dns: getaddrinfo_a(%s)=%d, errno=%d (%s)",
346 req->name, res, errno, strerror(errno));
347 } else {
348 log_warning("dns: getaddrinfo_a(%s)=%d", req->name, res);
349 }
350 list_del(&grq->node);
351 free(grq);
352 failed2:
353 req->done = true;
354 deliver_info(req);
355 }
356
impl_release(struct DNSContext * ctx)357 static void impl_release(struct DNSContext *ctx)
358 {
359 struct GaiContext *gctx = ctx->edns;
360 if (gctx) {
361 evsignal_del(&gctx->ev);
362 free(gctx);
363 ctx->edns = NULL;
364 }
365 }
366
367 #endif /* USE_GETADDRINFO_A */
368
369
370 /*
371 * ADNS with libevent2 <event2/dns.h>
372 */
373
374 #ifdef USE_EVDNS
375
adns_get_backend(void)376 const char *adns_get_backend(void)
377 {
378 return "evdns2";
379 }
380
381 /*
382 * Confusingly, this is not the same as evdns_err_to_string().
383 */
_evdns_base_resolv_conf_parse_err_to_string(int err)384 static const char *_evdns_base_resolv_conf_parse_err_to_string(int err)
385 {
386 switch (err) {
387 case 0: return "no error";
388 case 1: return "failed to open file";
389 case 2: return "failed to stat file";
390 case 3: return "file too large";
391 case 4: return "out of memory";
392 case 5: return "short read from file";
393 case 6: return "no nameservers listed in the file";
394 default: return "[Unknown error code]";
395 }
396 }
397
impl_init(struct DNSContext * ctx)398 static bool impl_init(struct DNSContext *ctx)
399 {
400 if (cf_resolv_conf && cf_resolv_conf[0]) {
401 int err;
402
403 ctx->edns = evdns_base_new(pgb_event_base, 0);
404 if (!ctx->edns) {
405 log_error("evdns_base_new failed");
406 return false;
407 }
408 err = evdns_base_resolv_conf_parse(ctx->edns, DNS_OPTIONS_ALL,
409 cf_resolv_conf);
410 if (err) {
411 log_error("evdns parsing of \"%s\" failed: %s",
412 cf_resolv_conf,
413 _evdns_base_resolv_conf_parse_err_to_string(err));
414 return false;
415 }
416 } else {
417 ctx->edns = evdns_base_new(pgb_event_base, 1);
418 if (!ctx->edns) {
419 log_error("evdns_base_new failed");
420 return false;
421 }
422 }
423 return true;
424 }
425
impl_launch_query(struct DNSRequest * req)426 static void impl_launch_query(struct DNSRequest *req)
427 {
428 static const struct addrinfo hints = { .ai_socktype = SOCK_STREAM };
429
430 struct evdns_getaddrinfo_request *gai_req;
431 struct evdns_base *dns = req->ctx->edns;
432
433 gai_req = evdns_getaddrinfo(dns, req->name, NULL, &hints, got_result_gai, req);
434 log_noise("dns: evdns_getaddrinfo(%s)=%p", req->name, gai_req);
435 }
436
impl_release(struct DNSContext * ctx)437 static void impl_release(struct DNSContext *ctx)
438 {
439 struct evdns_base *dns = ctx->edns;
440 evdns_base_free(dns, 0);
441 }
442
443 #endif /* USE_EVDNS */
444
445
446 /*
447 * ADNS with <udns.h>
448 */
449
450 #ifdef USE_UDNS
451
452 struct UdnsMeta {
453 struct dns_ctx *ctx;
454 struct event ev_io;
455 struct event ev_timer;
456 bool timer_active;
457 };
458
adns_get_backend(void)459 const char *adns_get_backend(void)
460 {
461 return "udns " UDNS_VERSION;
462 }
463
udns_timer_setter(struct dns_ctx * uctx,int timeout,void * arg)464 static void udns_timer_setter(struct dns_ctx *uctx, int timeout, void *arg)
465 {
466 struct DNSContext *ctx = arg;
467 struct UdnsMeta *udns = ctx->edns;
468
469 log_noise("udns_timer_setter: ctx=%p timeout=%d", uctx, timeout);
470
471 if (udns->timer_active) {
472 event_del(&udns->ev_timer);
473 udns->timer_active = false;
474 }
475
476 if (uctx && timeout >= 0) {
477 struct timeval tv = { .tv_sec = timeout, .tv_usec = 0 };
478 evtimer_add(&udns->ev_timer, &tv);
479 udns->timer_active = true;
480 }
481 }
482
udns_timer_cb(int d,short fl,void * arg)483 static void udns_timer_cb(int d, short fl, void *arg)
484 {
485 struct DNSContext *ctx = arg;
486 struct UdnsMeta *udns = ctx->edns;
487 time_t now = get_cached_time() / USEC;
488
489 log_noise("udns_timer_cb");
490
491 dns_timeouts(udns->ctx, 10, now);
492 }
493
udns_io_cb(int fd,short fl,void * arg)494 static void udns_io_cb(int fd, short fl, void *arg)
495 {
496 struct DNSContext *ctx = arg;
497 struct UdnsMeta *udns = ctx->edns;
498 time_t now = get_cached_time() / USEC;
499
500 log_noise("udns_io_cb");
501
502 dns_ioevent(udns->ctx, now);
503 }
504
udns_result_a4(struct dns_ctx * ctx,struct dns_rr_a4 * a4,void * data)505 static void udns_result_a4(struct dns_ctx *ctx, struct dns_rr_a4 *a4, void *data)
506 {
507 struct DNSRequest *req = data;
508 struct addrinfo *res = NULL;
509 int err;
510
511 err = dns_status(ctx);
512 if (err < 0) {
513 log_warning("udns_result_a4: %s: query failed [%d]", req->name, err);
514 } else if (a4) {
515 log_noise("udns_result_a4: %s: %d ips", req->name, a4->dnsa4_nrr);
516 res = convert_ipv4_result(a4->dnsa4_addr, a4->dnsa4_nrr);
517 free(a4);
518 } else {
519 log_warning("udns_result_a4: %s: missing result", req->name);
520 }
521 got_result_gai(0, res, req);
522 }
523
impl_launch_query(struct DNSRequest * req)524 static void impl_launch_query(struct DNSRequest *req)
525 {
526 struct UdnsMeta *udns = req->ctx->edns;
527 struct dns_query *q;
528 int flags = 0;
529
530 q = dns_submit_a4(udns->ctx, req->name, flags, udns_result_a4, req);
531 if (q) {
532 log_noise("dns: udns_launch_query(%s)=%p", req->name, q);
533 } else {
534 log_warning("dns: udns_launch_query(%s)=NULL", req->name);
535 }
536 }
537
impl_init(struct DNSContext * ctx)538 static bool impl_init(struct DNSContext *ctx)
539 {
540 int fd;
541 struct dns_ctx *dctx;
542 struct UdnsMeta *udns;
543 int err;
544
545 if (cf_resolv_conf && cf_resolv_conf[0]) {
546 log_error("resolv_conf setting is not supported by udns");
547 return false;
548 }
549
550 dns_init(NULL, 0);
551
552 dctx = dns_new(NULL);
553 if (!dctx)
554 return false;
555
556 udns = calloc(1, sizeof(*udns));
557 if (!udns)
558 return false;
559 ctx->edns = udns;
560 udns->ctx = dctx;
561
562 /* i/o callback setup */
563 fd = dns_open(dctx);
564 if (fd <= 0) {
565 log_error("dns_open failed: fd=%d", fd);
566 return false;
567 }
568 event_assign(&udns->ev_io, pgb_event_base, fd, EV_READ | EV_PERSIST, udns_io_cb, ctx);
569 err = event_add(&udns->ev_io, NULL);
570 if (err < 0)
571 log_warning("impl_init: event_add failed: %s", strerror(errno));
572
573 /* timer setup */
574 evtimer_assign(&udns->ev_timer, pgb_event_base, udns_timer_cb, ctx);
575 dns_set_tmcbck(udns->ctx, udns_timer_setter, ctx);
576
577 return true;
578 }
579
impl_release(struct DNSContext * ctx)580 static void impl_release(struct DNSContext *ctx)
581 {
582 struct UdnsMeta *udns = ctx->edns;
583
584 event_del(&udns->ev_io);
585 dns_free(udns->ctx);
586 if (udns->timer_active) {
587 event_del(&udns->ev_timer);
588 udns->timer_active = false;
589 }
590 }
591
592 /*
593 * generic SOA query for UDNS
594 */
595
596 struct SOA {
597 dns_rr_common(dnssoa);
598
599 char *dnssoa_nsname;
600 char *dnssoa_hostmaster;
601 uint32_t dnssoa_serial;
602 uint32_t dnssoa_refresh;
603 uint32_t dnssoa_retry;
604 uint32_t dnssoa_expire;
605 uint32_t dnssoa_minttl;
606 };
607
608 typedef void query_soa_fn(struct dns_ctx *ctx, struct SOA *result, void *data);
609
parse_soa(dnscc_t * qdn,dnscc_t * pkt,dnscc_t * cur,dnscc_t * end,void ** result)610 static int parse_soa(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, void **result)
611 {
612 struct SOA *soa = NULL;
613 int res, len;
614 struct dns_parse p;
615 struct dns_rr rr;
616 dnsc_t buf[DNS_MAXDN];
617 char *s;
618
619 /* calc size */
620 len = 0;
621 dns_initparse(&p, qdn, pkt, cur, end);
622 while ((res = dns_nextrr(&p, &rr)) > 0) {
623 cur = rr.dnsrr_dptr;
624
625 res = dns_getdn(pkt, &cur, end, buf, sizeof(buf));
626 if (res <= 0)
627 goto failed;
628 len += dns_dntop_size(buf);
629
630 res = dns_getdn(pkt, &cur, end, buf, sizeof(buf));
631 if (res <= 0)
632 goto failed;
633 len += dns_dntop_size(buf);
634
635 if (cur + 5*4 != rr.dnsrr_dend)
636 goto failed;
637 }
638 if (res < 0 || p.dnsp_nrr != 1)
639 goto failed;
640 len += dns_stdrr_size(&p);
641
642 /* allocate */
643 soa = malloc(sizeof(*soa) + len);
644 if (!soa)
645 return DNS_E_NOMEM;
646
647 /* fill with data */
648 soa->dnssoa_nrr = 1;
649 dns_rewind(&p, qdn);
650 dns_nextrr(&p, &rr);
651 s = (char *)(soa + 1);
652 cur = rr.dnsrr_dptr;
653
654 soa->dnssoa_nsname = s;
655 dns_getdn(pkt, &cur, end, buf, sizeof(buf));
656 s += dns_dntop(buf, s, DNS_MAXNAME);
657
658 soa->dnssoa_hostmaster = s;
659 dns_getdn(pkt, &cur, end, buf, sizeof(buf));
660 s += dns_dntop(buf, s, DNS_MAXNAME);
661
662 soa->dnssoa_serial = dns_get32(cur + 0*4);
663 soa->dnssoa_refresh = dns_get32(cur + 1*4);
664 soa->dnssoa_retry = dns_get32(cur + 2*4);
665 soa->dnssoa_expire = dns_get32(cur + 3*4);
666 soa->dnssoa_minttl = dns_get32(cur + 4*4);
667
668 dns_stdrr_finish((struct dns_rr_null *)soa, s, &p);
669
670 *result = soa;
671 return 0;
672 failed:
673 free(soa);
674 return DNS_E_PROTOCOL;
675 }
676
677 static struct dns_query *
submit_soa(struct dns_ctx * ctx,const char * name,int flags,query_soa_fn * cb,void * data)678 submit_soa(struct dns_ctx *ctx, const char *name, int flags, query_soa_fn *cb, void *data)
679 {
680 return dns_submit_p(ctx, name, DNS_C_IN, DNS_T_SOA, flags,
681 parse_soa, (dns_query_fn *)cb, data);
682 }
683
684 /*
685 * actual "get serial" part
686 */
687
udns_result_soa(struct dns_ctx * uctx,struct SOA * soa,void * data)688 static void udns_result_soa(struct dns_ctx *uctx, struct SOA *soa, void *data)
689 {
690 struct DNSContext *ctx = data;
691
692 if (!soa) {
693 log_noise("SOA query failed");
694 got_zone_serial(ctx, NULL);
695 return;
696 }
697
698 log_noise("SOA1: cname=%s qname=%s ttl=%u nrr=%u",
699 soa->dnssoa_cname, soa->dnssoa_qname,
700 soa->dnssoa_ttl, soa->dnssoa_nrr);
701 log_noise("SOA2: nsname=%s hostmaster=%s serial=%u refresh=%u retry=%u expire=%u minttl=%u",
702 soa->dnssoa_nsname, soa->dnssoa_hostmaster, soa->dnssoa_serial, soa->dnssoa_refresh,
703 soa->dnssoa_retry, soa->dnssoa_expire, soa->dnssoa_minttl);
704
705 got_zone_serial(ctx, &soa->dnssoa_serial);
706
707 free(soa);
708 }
709
impl_query_soa_serial(struct DNSContext * ctx,const char * zonename)710 static int impl_query_soa_serial(struct DNSContext *ctx, const char *zonename)
711 {
712 struct UdnsMeta *udns = ctx->edns;
713 struct dns_query *q;
714 int flags = 0;
715
716 log_debug("udns: impl_query_soa_serial: name=%s", zonename);
717 q = submit_soa(udns->ctx, zonename, flags, udns_result_soa, ctx);
718 if (!q) {
719 log_error("impl_query_soa_serial failed: %s", zonename);
720 }
721 return 0;
722 }
723
724 #endif /* USE_UDNS */
725
726
727 /*
728 * ADNS with <ares.h>
729 */
730
731 #ifdef USE_CARES
732
733 #define MAX_CARES_FDS 16
734
735 struct XaresFD {
736 struct event ev; /* fd event state is persistent */
737 struct XaresMeta *meta; /* pointer to parent context */
738 ares_socket_t sock; /* socket value */
739 short wait; /* EV_READ / EV_WRITE */
740 bool in_use; /* is this slot assigned */
741 };
742
743 struct XaresMeta {
744 /* c-ares descriptor */
745 ares_channel chan;
746
747 /* how many elements in fds array are in use */
748 int max_fds;
749
750 /* static array for fds */
751 struct XaresFD fds[MAX_CARES_FDS];
752
753 /* timer event is one-shot */
754 struct event ev_timer;
755
756 /* is timer activated? */
757 bool timer_active;
758
759 /* If dns events happened during event loop,
760 timer may need recalibration. */
761 bool got_events;
762
763 };
764
adns_get_backend(void)765 const char *adns_get_backend(void)
766 {
767 return "c-ares " ARES_VERSION_STR;
768 }
769
770
771 /* called by libevent on timer timeout */
xares_timer_cb(evutil_socket_t sock,short flags,void * arg)772 static void xares_timer_cb(evutil_socket_t sock, short flags, void *arg)
773 {
774 struct DNSContext *ctx = arg;
775 struct XaresMeta *meta = ctx->edns;
776
777 ares_process_fd(meta->chan, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
778
779 meta->timer_active = false;
780 meta->got_events = true;
781 }
782
783 /* called by libevent on fd event */
xares_fd_cb(evutil_socket_t sock,short flags,void * arg)784 static void xares_fd_cb(evutil_socket_t sock, short flags, void *arg)
785 {
786 struct XaresFD *xfd = arg;
787 struct XaresMeta *meta = xfd->meta;
788 ares_socket_t r, w;
789
790 r = (flags & EV_READ) ? xfd->sock : ARES_SOCKET_BAD;
791 w = (flags & EV_WRITE) ? xfd->sock : ARES_SOCKET_BAD;
792 ares_process_fd(meta->chan, r, w);
793
794 meta->got_events = true;
795 }
796
797 /* called by c-ares on new socket creation */
xares_new_socket_cb(ares_socket_t sock,int sock_type,void * arg)798 static int xares_new_socket_cb(ares_socket_t sock, int sock_type, void *arg)
799 {
800 struct DNSContext *ctx = arg;
801 struct XaresMeta *meta = ctx->edns;
802 struct XaresFD *xfd;
803 int pos;
804
805 /* find free slot in array */
806 for (pos = 0; pos < meta->max_fds; pos++) {
807 if (!meta->fds[pos].in_use)
808 break;
809 }
810 if (pos >= MAX_CARES_FDS) {
811 log_warning("c-ares fd overflow");
812 return ARES_ENOMEM;
813 }
814 if (pos == meta->max_fds)
815 meta->max_fds++;
816
817 /* fill it */
818 xfd = &meta->fds[pos];
819 xfd->meta = meta;
820 xfd->sock = sock;
821 xfd->wait = 0;
822 xfd->in_use = true;
823 return ARES_SUCCESS;
824 }
825
826 /* called by c-ares on socket state change (r=w=0 means socket close) */
xares_state_cb(void * arg,ares_socket_t sock,int r,int w)827 static void xares_state_cb(void *arg, ares_socket_t sock, int r, int w)
828 {
829 struct DNSContext *ctx = arg;
830 struct XaresMeta *meta = ctx->edns;
831 struct XaresFD *xfd;
832 int pos;
833 short new_wait = 0;
834
835 if (r)
836 new_wait |= EV_READ;
837 if (w)
838 new_wait |= EV_WRITE;
839
840 /* find socket */
841 for (pos = 0; pos < meta->max_fds; pos++) {
842 xfd = &meta->fds[pos];
843 if (!xfd->in_use)
844 continue;
845
846 if (xfd->sock != sock)
847 continue;
848
849 /* no change? */
850 if (xfd->wait == new_wait)
851 return;
852
853 goto re_set;
854 }
855
856 log_warning("adns: c-ares state change for unknown fd: %u", (unsigned)sock);
857 return;
858
859 re_set:
860 if (xfd->wait)
861 event_del(&xfd->ev);
862 xfd->wait = new_wait;
863 if (new_wait) {
864 event_assign(&xfd->ev, pgb_event_base, sock, new_wait | EV_PERSIST, xares_fd_cb, xfd);
865 if (event_add(&xfd->ev, NULL) < 0)
866 log_warning("adns: event_add failed: %s", strerror(errno));
867 } else {
868 xfd->in_use = false;
869 }
870 return;
871 }
872
873 /* called by c-ares on dns reply */
xares_host_cb(void * arg,int status,int timeouts,struct hostent * h)874 static void xares_host_cb(void *arg, int status, int timeouts, struct hostent *h)
875 {
876 struct DNSRequest *req = arg;
877 struct addrinfo *res = NULL;
878
879 log_noise("dns: xares_host_cb(%s)=%s", req->name, ares_strerror(status));
880 if (status == ARES_SUCCESS) {
881 res = convert_hostent(h);
882 got_result_gai(0, res, req);
883 } else {
884 log_debug("DNS lookup failed: %s - %s", req->name, ares_strerror(status));
885 got_result_gai(0, res, req);
886 }
887 }
888
889 /* send hostname query */
impl_launch_query(struct DNSRequest * req)890 static void impl_launch_query(struct DNSRequest *req)
891 {
892 struct XaresMeta *meta = req->ctx->edns;
893 int af;
894
895 /*
896 * c-ares <= 1.10 cannot resolve CNAME with AF_UNSPEC.
897 *
898 * Force IPv4 there.
899 *
900 * Fixed in "host_callback: Fall back to AF_INET on searching with AF_UNSPEC" (c1fe47f)
901 * in c-ares repo.
902 */
903 #if ARES_VERSION <= 0x10A00
904 #warning c-ares <=1.10 has buggy IPv6 support; this PgBouncer build will use IPv4 only.
905 af = AF_INET;
906 #else
907 af = AF_UNSPEC;
908 #endif
909 log_noise("dns: ares_gethostbyname(%s)", req->name);
910 ares_gethostbyname(meta->chan, req->name, af, xares_host_cb, req);
911
912 meta->got_events = true;
913 }
914
915 /* re-set timer if any dns event happened */
impl_per_loop(struct DNSContext * ctx)916 static void impl_per_loop(struct DNSContext *ctx)
917 {
918 struct timeval tv, *tvp;
919 struct XaresMeta *meta = ctx->edns;
920
921 if (!meta->got_events)
922 return;
923
924 if (meta->timer_active) {
925 event_del(&meta->ev_timer);
926 meta->timer_active = false;
927 }
928
929 tvp = ares_timeout(meta->chan, NULL, &tv);
930 if (tvp != NULL) {
931 if (event_add(&meta->ev_timer, tvp) < 0)
932 log_warning("impl_per_loop: event_add failed: %s", strerror(errno));
933 meta->timer_active = true;
934 }
935
936 meta->got_events = false;
937 }
938
939 /* c-ares setup */
impl_init(struct DNSContext * ctx)940 static bool impl_init(struct DNSContext *ctx)
941 {
942 struct XaresMeta *meta;
943 int err;
944 int mask;
945 struct ares_options opts;
946
947 err = ares_library_init(ARES_LIB_INIT_ALL);
948 if (err) {
949 log_error("ares_library_init: %s", ares_strerror(err));
950 return false;
951 }
952
953 meta = calloc(1, sizeof(*meta));
954 if (!meta)
955 return false;
956
957 memset(&opts, 0, sizeof(opts));
958 opts.sock_state_cb = xares_state_cb;
959 opts.sock_state_cb_data = ctx;
960 mask = ARES_OPT_SOCK_STATE_CB;
961 if (cf_resolv_conf && cf_resolv_conf[0]) {
962 #ifdef ARES_OPT_RESOLVCONF
963 opts.resolvconf_path = strdup(cf_resolv_conf);
964 if (!opts.resolvconf_path) {
965 free(meta);
966 return false;
967 }
968 mask |= ARES_OPT_RESOLVCONF;
969 #else
970 log_error("resolv_conf setting is not supported by this version of c-ares");
971 free(meta);
972 return false;
973 #endif
974 }
975
976 err = ares_init_options(&meta->chan, &opts, mask);
977 if (err) {
978 free(meta);
979 log_error("ares_library_init: %s", ares_strerror(err));
980 return false;
981 }
982
983 ares_set_socket_callback(meta->chan, xares_new_socket_cb, ctx);
984
985 evtimer_assign(&meta->ev_timer, pgb_event_base, xares_timer_cb, ctx);
986
987 ctx->edns = meta;
988 return true;
989 }
990
991 /* c-ares shutdown */
impl_release(struct DNSContext * ctx)992 static void impl_release(struct DNSContext *ctx)
993 {
994 struct XaresMeta *meta = ctx->edns;
995
996 ares_destroy(meta->chan);
997 ares_library_cleanup();
998
999 if (meta->timer_active)
1000 event_del(&meta->ev_timer);
1001
1002 free(meta);
1003 ctx->edns = NULL;
1004 }
1005
1006 /*
1007 * query SOA with c-ares
1008 */
1009
1010 #ifndef HAVE_ARES_PARSE_SOA_REPLY
1011
1012 #define ares_soa_reply xares_soa_reply
1013 #define ares_parse_soa_reply xares_parse_soa_reply
1014
1015 struct ares_soa_reply {
1016 char *nsname;
1017 char *hostmaster;
1018 uint32_t serial;
1019 uint32_t refresh;
1020 uint32_t retry;
1021 uint32_t expire;
1022 uint32_t minttl;
1023 };
1024
xares_free_soa(struct ares_soa_reply * soa)1025 static void xares_free_soa(struct ares_soa_reply *soa)
1026 {
1027 if (soa) {
1028 if (soa->nsname)
1029 free(soa->nsname);
1030 if (soa->hostmaster)
1031 free(soa->hostmaster);
1032 free(soa);
1033 }
1034 }
1035
1036 /*
1037 * Full SOA reply packet structure (rfc1035)
1038 *
1039 * 1) header
1040 * id:16, flags:16, qdcount:16, ancount:16, nscount:16, arcount:16
1041 *
1042 * 2) query (qdcount)
1043 * qname:name, qtype:16, qclass:16
1044 *
1045 * 3) answer (ancount)
1046 * name:name, type:16, class:16, ttl:32, rdlength:16
1047 *
1048 * 3.1) soa rdata
1049 * nsname:name, hostmaster:name,
1050 * serial:32, refresh:32, retry:32, expire:32, minimum:32
1051 *
1052 * 4) authority (nscount) - ignored
1053 *
1054 * 5) additional (arcount) - ignored
1055 */
ares_parse_soa_reply(const unsigned char * abuf,int alen,struct ares_soa_reply ** soa_p)1056 static int ares_parse_soa_reply(const unsigned char *abuf, int alen, struct ares_soa_reply **soa_p)
1057 {
1058 const unsigned char *aptr;
1059 long len;
1060 char *qname = NULL, *rr_name = NULL;
1061 struct ares_soa_reply *soa = NULL;
1062 int qdcount, ancount;
1063 int status;
1064
1065 if (alen < NS_HFIXEDSZ)
1066 return ARES_EBADRESP;
1067
1068 /* parse message header */
1069 qdcount = DNS_HEADER_QDCOUNT(abuf);
1070 ancount = DNS_HEADER_ANCOUNT(abuf);
1071 if (qdcount != 1 || ancount != 1)
1072 return ARES_EBADRESP;
1073 aptr = abuf + NS_HFIXEDSZ;
1074
1075 /* allocate result struct */
1076 soa = calloc(1, sizeof(*soa));
1077 if (!soa)
1078 return ARES_ENOMEM;
1079
1080 /* parse query */
1081 status = ares_expand_name(aptr, abuf, alen, &qname, &len);
1082 if (status != ARES_SUCCESS)
1083 goto failed_stat;
1084 aptr += len;
1085
1086 /* skip qtype & qclass */
1087 if (aptr + NS_QFIXEDSZ > abuf + alen)
1088 goto failed;
1089 aptr += NS_QFIXEDSZ;
1090
1091 /* parse RR header */
1092 status = ares_expand_name(aptr, abuf, alen, &rr_name, &len);
1093 if (status != ARES_SUCCESS)
1094 goto failed_stat;
1095 aptr += len;
1096
1097 /* skip rr_type, rr_class, rr_ttl, rr_rdlen */
1098 if (aptr + NS_RRFIXEDSZ > abuf + alen)
1099 goto failed;
1100 aptr += NS_RRFIXEDSZ;
1101
1102 /* nsname */
1103 status = ares_expand_name(aptr, abuf, alen, &soa->nsname, &len);
1104 if (status != ARES_SUCCESS)
1105 goto failed_stat;
1106 aptr += len;
1107
1108 /* hostmaster */
1109 status = ares_expand_name(aptr, abuf, alen, &soa->hostmaster, &len);
1110 if (status != ARES_SUCCESS)
1111 goto failed_stat;
1112 aptr += len;
1113
1114 /* integer fields */
1115 if (aptr + 5*4 > abuf + alen)
1116 goto failed;
1117 soa->serial = DNS__32BIT(aptr + 0*4);
1118 soa->refresh = DNS__32BIT(aptr + 1*4);
1119 soa->retry = DNS__32BIT(aptr + 2*4);
1120 soa->expire = DNS__32BIT(aptr + 3*4);
1121 soa->minttl = DNS__32BIT(aptr + 4*4);
1122
1123 log_noise("ares SOA result: qname=%s rr_name=%s serial=%u", qname, rr_name, soa->serial);
1124
1125 free(qname);
1126 free(rr_name);
1127
1128 *soa_p = soa;
1129
1130 return ARES_SUCCESS;
1131
1132 failed:
1133 status = ARES_EBADRESP;
1134
1135 failed_stat:
1136 xares_free_soa(soa);
1137 if (qname)
1138 free(qname);
1139 if (rr_name)
1140 free(rr_name);
1141 return (status == ARES_EBADNAME) ? ARES_EBADRESP : status;
1142 }
1143
1144 #else /* HAVE_ARES_PARSE_SOA_REPLY */
1145
xares_free_soa(struct ares_soa_reply * soa)1146 static void xares_free_soa(struct ares_soa_reply *soa)
1147 {
1148 ares_free_data(soa);
1149 }
1150
1151 #endif /* HAVE_ARES_PARSE_SOA_REPLY */
1152
1153
1154 /* called by c-ares on SOA reply */
xares_soa_cb(void * arg,int status,int timeouts,unsigned char * abuf,int alen)1155 static void xares_soa_cb(void *arg, int status, int timeouts,
1156 unsigned char *abuf, int alen)
1157 {
1158 struct DNSContext *ctx = arg;
1159 struct XaresMeta *meta = ctx->edns;
1160 struct ares_soa_reply *soa = NULL;
1161
1162 meta->got_events = true;
1163
1164 log_noise("ares SOA result: %s", ares_strerror(status));
1165 if (status != ARES_SUCCESS) {
1166 got_zone_serial(ctx, NULL);
1167 return;
1168 }
1169
1170 status = ares_parse_soa_reply(abuf, alen, &soa);
1171 if (status == ARES_SUCCESS) {
1172 got_zone_serial(ctx, &soa->serial);
1173 } else {
1174 log_warning("ares_parse_soa: %s", ares_strerror(status));
1175 got_zone_serial(ctx, NULL);
1176 }
1177
1178 xares_free_soa(soa);
1179 }
1180
1181 /* send SOA query */
impl_query_soa_serial(struct DNSContext * ctx,const char * zonename)1182 static int impl_query_soa_serial(struct DNSContext *ctx, const char *zonename)
1183 {
1184 struct XaresMeta *meta = ctx->edns;
1185
1186 log_debug("dns: ares query SOA(%s)", zonename);
1187 ares_search(meta->chan, zonename, ns_c_in, ns_t_soa,
1188 xares_soa_cb, ctx);
1189
1190 meta->got_events = true;
1191 return 0;
1192 }
1193
1194 #endif /* USE_CARES */
1195
1196
1197 /*
1198 * Generic framework
1199 */
1200
deliver_info(struct DNSRequest * req)1201 static void deliver_info(struct DNSRequest *req)
1202 {
1203 struct DNSContext *ctx = req->ctx;
1204 struct DNSToken *ucb;
1205 struct List *el;
1206 const struct addrinfo *ai = req->current;
1207 char sabuf[128];
1208
1209 ctx->active--;
1210
1211 loop:
1212 /* get next req */
1213 el = list_pop(&req->ucb_list);
1214 if (!el)
1215 return;
1216 ucb = container_of(el, struct DNSToken, node);
1217
1218 /* launch callback */
1219 log_noise("dns: deliver_info(%s) addr=%s", req->name,
1220 ai ? sa2str(ai->ai_addr, sabuf, sizeof(sabuf)) : "NULL");
1221 ucb->cb_func(ucb->cb_arg,
1222 ai ? ai->ai_addr : NULL,
1223 ai ? ai->ai_addrlen : 0);
1224 free(ucb);
1225
1226 /* scroll req list */
1227 if (ai) {
1228 req->current = ai->ai_next;
1229 if (!req->current)
1230 req->current = req->result;
1231 }
1232
1233 goto loop;
1234 }
1235
req_cmp(uintptr_t arg,struct AANode * node)1236 static int req_cmp(uintptr_t arg, struct AANode *node)
1237 {
1238 const char *s1 = (char *)arg;
1239 struct DNSRequest *req = container_of(node, struct DNSRequest, node);
1240 return strcmp(s1, req->name);
1241 }
1242
req_reset(struct DNSRequest * req)1243 static void req_reset(struct DNSRequest *req)
1244 {
1245 req->done = false;
1246 if (req->result) {
1247 if (req->oldres)
1248 freeaddrinfo(req->oldres);
1249 req->oldres = req->result;
1250 }
1251 req->result = req->current = NULL;
1252 }
1253
req_free(struct AANode * node,void * arg)1254 static void req_free(struct AANode *node, void *arg)
1255 {
1256 struct DNSToken *ucb;
1257 struct DNSRequest *req;
1258 struct List *el;
1259 req = container_of(node, struct DNSRequest, node);
1260 while ((el = list_pop(&req->ucb_list)) != NULL) {
1261 ucb = container_of(el, struct DNSToken, node);
1262 free(ucb);
1263 }
1264 req_reset(req);
1265 if (req->oldres) {
1266 freeaddrinfo(req->oldres);
1267 req->oldres = NULL;
1268 }
1269 if (req->zone)
1270 statlist_remove(&req->zone->host_list, &req->znode);
1271 free(req->name);
1272 free(req);
1273 }
1274
adns_create_context(void)1275 struct DNSContext *adns_create_context(void)
1276 {
1277 struct DNSContext *ctx;
1278
1279 log_debug("adns_create_context: %s", adns_get_backend());
1280
1281 ctx = calloc(1, sizeof(*ctx));
1282 if (!ctx)
1283 return NULL;
1284
1285 aatree_init(&ctx->req_tree, req_cmp, req_free);
1286 zone_init(ctx);
1287
1288 if (!impl_init(ctx)) {
1289 adns_free_context(ctx);
1290 return NULL;
1291 }
1292 return ctx;
1293 }
1294
adns_free_context(struct DNSContext * ctx)1295 void adns_free_context(struct DNSContext *ctx)
1296 {
1297 if (ctx) {
1298 impl_release(ctx);
1299 aatree_destroy(&ctx->req_tree);
1300 zone_free(ctx);
1301 free(ctx);
1302 }
1303 }
1304
adns_resolve(struct DNSContext * ctx,const char * name,adns_callback_f cb_func,void * cb_arg)1305 struct DNSToken *adns_resolve(struct DNSContext *ctx, const char *name, adns_callback_f cb_func, void *cb_arg)
1306 {
1307 int namelen = strlen(name);
1308 struct DNSRequest *req;
1309 struct DNSToken *ucb;
1310 struct AANode *node;
1311
1312 /* setup actual lookup */
1313 node = aatree_search(&ctx->req_tree, (uintptr_t)name);
1314 if (node) {
1315 req = container_of(node, struct DNSRequest, node);
1316 } else {
1317 log_noise("dns: new req: %s", name);
1318 req = calloc(1, sizeof(*req));
1319 if (!req)
1320 goto nomem;
1321 req->name = strdup(name);
1322 if (!req->name) {
1323 free(req);
1324 goto nomem;
1325 }
1326 req->ctx = ctx;
1327 req->namelen = namelen;
1328 list_init(&req->ucb_list);
1329 list_init(&req->znode);
1330 aatree_insert(&ctx->req_tree, (uintptr_t)req->name, &req->node);
1331
1332 zone_register(ctx, req);
1333
1334 ctx->active++;
1335 impl_launch_query(req);
1336 }
1337
1338 /* remember user callback */
1339 ucb = calloc(1, sizeof(*ucb));
1340 if (!ucb)
1341 goto nomem;
1342 list_init(&ucb->node);
1343 ucb->cb_func = cb_func;
1344 ucb->cb_arg = cb_arg;
1345 list_append(&req->ucb_list, &ucb->node);
1346
1347 /* if already have final result, report it */
1348 if (req->done) {
1349 if (req->res_ttl < get_cached_time()) {
1350 log_noise("dns: ttl over: %s", req->name);
1351 req_reset(req);
1352 ctx->active++;
1353 impl_launch_query(req);
1354 } else {
1355 deliver_info(req);
1356 }
1357 }
1358 /* if ->done, then we have already reported */
1359 return req->done ? NULL : ucb;
1360 nomem:
1361 log_warning("dns(%s): req failed, no mem", name);
1362 cb_func(cb_arg, NULL, 0);
1363 return NULL;
1364 }
1365
cmp_addrinfo(const struct addrinfo * a1,const struct addrinfo * a2)1366 static int cmp_addrinfo(const struct addrinfo *a1, const struct addrinfo *a2)
1367 {
1368 if (a1->ai_family != a2->ai_family)
1369 return a1->ai_family - a2->ai_family;
1370 if (a1->ai_addrlen != a2->ai_addrlen)
1371 return a1->ai_addrlen - a2->ai_addrlen;
1372
1373 return memcmp(a1->ai_addr, a2->ai_addr, a1->ai_addrlen);
1374 }
1375
1376 /* check if new dns reply is missing some IP compared to old one */
check_req_result_changes(struct DNSRequest * req)1377 static void check_req_result_changes(struct DNSRequest *req)
1378 {
1379 struct addrinfo *ai, *aj;
1380
1381 for (ai = req->oldres; ai; ai = ai->ai_next) {
1382 bool found = false;
1383 for (aj = req->result; aj; aj = aj->ai_next) {
1384 if (cmp_addrinfo(ai, aj) == 0) {
1385 found = true;
1386 break;
1387 }
1388 }
1389
1390 /* missing IP (possible DNS failover) make connections to it dirty */
1391 if (!found)
1392 tag_host_addr_dirty(req->name, ai->ai_addr);
1393 }
1394 }
1395
1396 /* struct addrinfo -> deliver_info() */
got_result_gai(int result,struct addrinfo * res,void * arg)1397 static void got_result_gai(int result, struct addrinfo *res, void *arg)
1398 {
1399 struct DNSRequest *req = arg;
1400
1401 req_reset(req);
1402
1403 if (result == 0 && res) {
1404 req->result = res;
1405 req->current = res;
1406
1407 if (req->oldres)
1408 check_req_result_changes(req);
1409
1410 /* show all results */
1411 if (cf_verbose > 1) {
1412 const struct addrinfo *ai = res;
1413 int n = 0;
1414 char buf[128];
1415 while (ai) {
1416 log_noise("DNS: %s[%d] = %s [%s]", req->name, n++,
1417 sa2str(ai->ai_addr, buf, sizeof(buf)),
1418 ai->ai_socktype == SOCK_STREAM ? "STREAM" : "OTHER");
1419 ai = ai->ai_next;
1420 }
1421 }
1422 req->res_ttl = get_cached_time() + cf_dns_max_ttl;
1423 } else {
1424 /* lookup failed */
1425 log_warning("DNS lookup failed: %s: result=%d", req->name, result);
1426 req->res_ttl = get_cached_time() + cf_dns_nxdomain_ttl;
1427 }
1428
1429 req->done = true;
1430
1431 deliver_info(req);
1432 }
1433
adns_cancel(struct DNSContext * ctx,struct DNSToken * tk)1434 void adns_cancel(struct DNSContext *ctx, struct DNSToken *tk)
1435 {
1436 list_del(&tk->node);
1437 memset(tk, 0, sizeof(*tk));
1438 free(tk);
1439 }
1440
adns_info(struct DNSContext * ctx,int * names,int * zones,int * queries,int * pending)1441 void adns_info(struct DNSContext *ctx, int *names, int *zones, int *queries, int *pending)
1442 {
1443 *names = ctx->req_tree.count;
1444 *zones = ctx->zone_tree.count;
1445 *queries = ctx->active;
1446 *pending = 0;
1447 }
1448
1449 /*
1450 * zone code
1451 */
1452
zone_item_free(struct AANode * n,void * arg)1453 static void zone_item_free(struct AANode *n, void *arg)
1454 {
1455 struct DNSZone *z = container_of(n, struct DNSZone, tnode);
1456
1457 list_del(&z->lnode);
1458 free(z->zonename);
1459 free(z);
1460 }
1461
zone_item_cmp(uintptr_t val1,struct AANode * n2)1462 static int zone_item_cmp(uintptr_t val1, struct AANode *n2)
1463 {
1464 const char *name1 = (const char *)val1;
1465 struct DNSZone *z2 = container_of(n2, struct DNSZone, tnode);
1466 return strcasecmp(name1, z2->zonename);
1467 }
1468
zone_init(struct DNSContext * ctx)1469 static void zone_init(struct DNSContext *ctx)
1470 {
1471 aatree_init(&ctx->zone_tree, zone_item_cmp, zone_item_free);
1472 list_init(&ctx->zone_list);
1473 }
1474
zone_free(struct DNSContext * ctx)1475 static void zone_free(struct DNSContext *ctx)
1476 {
1477 aatree_destroy(&ctx->zone_tree);
1478 }
1479
zone_register(struct DNSContext * ctx,struct DNSRequest * req)1480 static void zone_register(struct DNSContext *ctx, struct DNSRequest *req)
1481 {
1482 struct DNSZone *z;
1483 struct AANode *n;
1484 const char *name;
1485
1486 log_debug("zone_register(%s)", req->name);
1487
1488 name = strchr(req->name, '.');
1489 if (!name || name[1] == 0)
1490 return;
1491 name++;
1492 log_debug("zone_register(%s): name=%s", req->name, name);
1493
1494 n = aatree_search(&ctx->zone_tree, (uintptr_t)name);
1495 if (n) {
1496 /* already exists */
1497 z = container_of(n, struct DNSZone, tnode);
1498 req->zone = z;
1499 statlist_append(&z->host_list, &req->znode);
1500 return;
1501 }
1502
1503 /* create struct */
1504 z = calloc(1, sizeof(*z));
1505 if (!z)
1506 return;
1507 z->zonename = strdup(name);
1508 if (!z->zonename) {
1509 free(z);
1510 return;
1511 }
1512 statlist_init(&z->host_list, "host_list");
1513 list_init(&z->lnode);
1514
1515 /* link */
1516 aatree_insert(&ctx->zone_tree, (uintptr_t)z->zonename, &z->tnode);
1517 list_append(&ctx->zone_list, &z->lnode);
1518 statlist_append(&z->host_list, &req->znode);
1519 req->zone = z;
1520 }
1521
zone_timer(evutil_socket_t fd,short flg,void * arg)1522 static void zone_timer(evutil_socket_t fd, short flg, void *arg)
1523 {
1524 struct DNSContext *ctx = arg;
1525 struct List *el;
1526 struct DNSZone *z;
1527
1528 if (list_empty(&ctx->zone_list)) {
1529 ctx->zone_state = 0;
1530 return;
1531 }
1532
1533 el = list_first(&ctx->zone_list);
1534 z = container_of(el, struct DNSZone, lnode);
1535 ctx->zone_state = 1;
1536 ctx->cur_zone = z;
1537 ctx->active++;
1538 impl_query_soa_serial(ctx, z->zonename);
1539 }
1540
launch_zone_timer(struct DNSContext * ctx)1541 static void launch_zone_timer(struct DNSContext *ctx)
1542 {
1543 struct timeval tv;
1544
1545 tv.tv_sec = cf_dns_zone_check_period / USEC;
1546 tv.tv_usec = cf_dns_zone_check_period % USEC;
1547
1548 evtimer_assign(&ctx->ev_zone_timer, pgb_event_base, zone_timer, ctx);
1549 safe_evtimer_add(&ctx->ev_zone_timer, &tv);
1550
1551 ctx->zone_state = 2;
1552 }
1553
adns_zone_cache_maint(struct DNSContext * ctx)1554 void adns_zone_cache_maint(struct DNSContext *ctx)
1555 {
1556 if (!cf_dns_zone_check_period) {
1557 if (ctx->zone_state == 2) {
1558 event_del(&ctx->ev_zone_timer);
1559 ctx->zone_state = 0;
1560 }
1561 ctx->cur_zone = NULL;
1562 return;
1563 } else if (ctx->zone_state == 0) {
1564 if (list_empty(&ctx->zone_list))
1565 return;
1566 launch_zone_timer(ctx);
1567 }
1568 }
1569
zone_requeue(struct DNSContext * ctx,struct DNSZone * z)1570 static void zone_requeue(struct DNSContext *ctx, struct DNSZone *z)
1571 {
1572 struct List *el;
1573 struct DNSRequest *req;
1574 statlist_for_each(el, &z->host_list) {
1575 req = container_of(el, struct DNSRequest, znode);
1576 if (!req->done)
1577 continue;
1578 req->res_ttl = 0;
1579 ctx->active++;
1580 impl_launch_query(req);
1581 }
1582 }
1583
got_zone_serial(struct DNSContext * ctx,uint32_t * serial)1584 static void got_zone_serial(struct DNSContext *ctx, uint32_t *serial)
1585 {
1586 struct DNSZone *z = ctx->cur_zone;
1587 struct List *el;
1588
1589 ctx->active--;
1590
1591 if (!ctx->zone_state || !z)
1592 return;
1593
1594 if (serial) {
1595 /* wraparound compare */
1596 int32_t s1 = z->serial;
1597 int32_t s2 = *serial;
1598 int32_t ds = s2 - s1;
1599 if (ds > 0) {
1600 log_info("zone '%s' serial changed: old=%u new=%u",
1601 z->zonename, z->serial, *serial);
1602 z->serial = *serial;
1603 zone_requeue(ctx, z);
1604 } else {
1605 log_debug("zone '%s' unchanged: serial=%u", z->zonename, *serial);
1606 }
1607 } else {
1608 log_debug("failure to get zone '%s' serial", z->zonename);
1609 }
1610
1611 el = z->lnode.next;
1612 if (el != &ctx->zone_list) {
1613 z = container_of(el, struct DNSZone, lnode);
1614 ctx->cur_zone = z;
1615
1616 ctx->active++;
1617 impl_query_soa_serial(ctx, z->zonename);
1618 } else {
1619 launch_zone_timer(ctx);
1620 }
1621 }
1622
1623 /*
1624 * Cache walkers
1625 */
1626
1627 struct WalkInfo {
1628 adns_walk_name_f name_cb;
1629 adns_walk_zone_f zone_cb;
1630 void *arg;
1631 };
1632
walk_name(struct AANode * n,void * arg)1633 static void walk_name(struct AANode *n, void *arg)
1634 {
1635 struct WalkInfo *w = arg;
1636 struct DNSRequest *req = container_of(n, struct DNSRequest, node);
1637
1638 w->name_cb(w->arg, req->name, req->result, req->res_ttl);
1639 }
1640
walk_zone(struct AANode * n,void * arg)1641 static void walk_zone(struct AANode *n, void *arg)
1642 {
1643 struct WalkInfo *w = arg;
1644 struct DNSZone *z = container_of(n, struct DNSZone, tnode);
1645
1646 w->zone_cb(w->arg, z->zonename, z->serial, statlist_count(&z->host_list));
1647 }
1648
adns_walk_names(struct DNSContext * ctx,adns_walk_name_f cb,void * arg)1649 void adns_walk_names(struct DNSContext *ctx, adns_walk_name_f cb, void *arg)
1650 {
1651 struct WalkInfo w;
1652 w.name_cb = cb;
1653 w.arg = arg;
1654 aatree_walk(&ctx->req_tree, AA_WALK_IN_ORDER, walk_name, &w);
1655 }
1656
adns_walk_zones(struct DNSContext * ctx,adns_walk_zone_f cb,void * arg)1657 void adns_walk_zones(struct DNSContext *ctx, adns_walk_zone_f cb, void *arg)
1658 {
1659 struct WalkInfo w;
1660 w.zone_cb = cb;
1661 w.arg = arg;
1662 aatree_walk(&ctx->zone_tree, AA_WALK_IN_ORDER, walk_zone, &w);
1663 }
1664
adns_per_loop(struct DNSContext * ctx)1665 void adns_per_loop(struct DNSContext *ctx)
1666 {
1667 impl_per_loop(ctx);
1668 }
1669