2 * Copyright (c) 1998-2012 by the citadel.org team
4 * This program is open source software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
18 * Inspired by NodeJS.org; thanks for the MX-Parser ;-)
30 #include <sys/types.h>
33 #if TIME_WITH_SYS_TIME
34 # include <sys/time.h>
38 # include <sys/time.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
51 #include <libcitadel.h>
54 #include "citserver.h"
57 #include "ctdl_module.h"
58 #include "event_client.h"
62 extern struct ev_loop *event_base;
64 void SockStateCb(void *data, int sock, int read, int write);
67 static void HostByAddrCb(void *data,
70 struct hostent *hostent)
74 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
76 EV_DNS_LOGT_STOP(DNS.timeout);
77 ev_timer_stop (event_base, &IO->DNS.timeout);
79 IO->DNS.Query->DNSStatus = status;
80 if (status != ARES_SUCCESS) {
81 StrBufPlain(IO->ErrMsg, ares_strerror(status), -1);
84 IO->DNS.Query->Data = hostent;
87 static void ParseAnswerA(AsyncIO *IO, unsigned char* abuf, int alen)
89 struct hostent* host = NULL;
91 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
93 if (IO->DNS.Query->VParsedDNSReply != NULL)
94 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
95 IO->DNS.Query->VParsedDNSReply = NULL;
97 IO->DNS.Query->DNSStatus = ares_parse_a_reply(abuf,
102 if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
104 ares_free_hostent(host);
105 StrBufPlain(IO->ErrMsg,
106 ares_strerror(IO->DNS.Query->DNSStatus), -1);
109 IO->DNS.Query->VParsedDNSReply = host;
110 IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
114 static void ParseAnswerAAAA(AsyncIO *IO, unsigned char* abuf, int alen)
116 struct hostent* host = NULL;
118 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
120 if (IO->DNS.Query->VParsedDNSReply != NULL)
121 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
122 IO->DNS.Query->VParsedDNSReply = NULL;
124 IO->DNS.Query->DNSStatus = ares_parse_aaaa_reply(abuf,
129 if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
131 ares_free_hostent(host);
132 StrBufPlain(IO->ErrMsg,
133 ares_strerror(IO->DNS.Query->DNSStatus), -1);
136 IO->DNS.Query->VParsedDNSReply = host;
137 IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
141 static void ParseAnswerCNAME(AsyncIO *IO, unsigned char* abuf, int alen)
143 struct hostent* host = NULL;
145 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
147 if (IO->DNS.Query->VParsedDNSReply != NULL)
148 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
149 IO->DNS.Query->VParsedDNSReply = NULL;
151 IO->DNS.Query->DNSStatus = ares_parse_a_reply(abuf,
156 if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
158 ares_free_hostent(host);
159 StrBufPlain(IO->ErrMsg,
160 ares_strerror(IO->DNS.Query->DNSStatus), -1);
164 // a CNAME lookup always returns a single record but
165 IO->DNS.Query->VParsedDNSReply = host;
166 IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
170 static void ParseAnswerMX(AsyncIO *IO, unsigned char* abuf, int alen)
172 struct ares_mx_reply *mx_out = NULL;
174 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
176 if (IO->DNS.Query->VParsedDNSReply != NULL)
177 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
178 IO->DNS.Query->VParsedDNSReply = NULL;
180 IO->DNS.Query->DNSStatus = ares_parse_mx_reply(abuf, alen, &mx_out);
181 if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
183 ares_free_data(mx_out);
184 StrBufPlain(IO->ErrMsg,
185 ares_strerror(IO->DNS.Query->DNSStatus), -1);
189 IO->DNS.Query->VParsedDNSReply = mx_out;
190 IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data;
194 static void ParseAnswerNS(AsyncIO *IO, unsigned char* abuf, int alen)
196 struct hostent* host = NULL;
198 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
200 if (IO->DNS.Query->VParsedDNSReply != NULL)
201 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
202 IO->DNS.Query->VParsedDNSReply = NULL;
204 IO->DNS.Query->DNSStatus = ares_parse_ns_reply(abuf, alen, &host);
205 if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
207 ares_free_hostent(host);
208 StrBufPlain(IO->ErrMsg,
209 ares_strerror(IO->DNS.Query->DNSStatus), -1);
212 IO->DNS.Query->VParsedDNSReply = host;
213 IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
217 static void ParseAnswerSRV(AsyncIO *IO, unsigned char* abuf, int alen)
219 struct ares_srv_reply *srv_out = NULL;
221 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
223 if (IO->DNS.Query->VParsedDNSReply != NULL)
224 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
225 IO->DNS.Query->VParsedDNSReply = NULL;
227 IO->DNS.Query->DNSStatus = ares_parse_srv_reply(abuf, alen, &srv_out);
228 if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
230 ares_free_data(srv_out);
231 StrBufPlain(IO->ErrMsg,
232 ares_strerror(IO->DNS.Query->DNSStatus), -1);
236 IO->DNS.Query->VParsedDNSReply = srv_out;
237 IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data;
241 static void ParseAnswerTXT(AsyncIO *IO, unsigned char* abuf, int alen)
243 struct ares_txt_reply *txt_out;
245 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
247 if (IO->DNS.Query->VParsedDNSReply != NULL)
248 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
249 IO->DNS.Query->VParsedDNSReply = NULL;
251 IO->DNS.Query->DNSStatus = ares_parse_txt_reply(abuf, alen, &txt_out);
252 if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
254 ares_free_data(txt_out);
255 StrBufPlain(IO->ErrMsg,
256 ares_strerror(IO->DNS.Query->DNSStatus), -1);
259 IO->DNS.Query->VParsedDNSReply = txt_out;
260 IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data;
263 void QueryCb(void *arg,
271 SetEVState(IO, eCaresStart);
272 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
274 EV_DNS_LOGT_STOP(DNS.timeout);
275 ev_timer_stop (event_base, &IO->DNS.timeout);
277 IO->DNS.Query->DNSStatus = status;
278 if (status == ARES_SUCCESS)
279 IO->DNS.Query->DNS_CB(arg, abuf, alen);
281 EV_DNS_syslog(LOG_DEBUG, "C-ARES: Failed by: %s error %s\n",
283 ares_strerror(status));
284 StrBufPrintf(IO->ErrMsg,
286 IO->DNS.Query->QueryTYPE,
287 (IO->DNS.Query->QStr != NULL)? IO->DNS.Query->QStr : "",
288 ares_strerror(status));
289 IO->DNS.Query->DNSStatus = status;
292 ev_idle_init(&IO->unwind_stack,
293 IO_postdns_callback);
294 IO->unwind_stack.data = IO;
295 EV_DNS_LOGT_INIT(unwind_stack);
296 EV_DNS_LOGT_START(unwind_stack);
297 ev_idle_start(event_base, &IO->unwind_stack);
300 void QueryCbDone(AsyncIO *IO)
302 SetEVState(IO, eCaresDoneIO);
303 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
305 EV_DNS_LOGT_STOP(DNS.timeout);
306 ev_timer_stop (event_base, &IO->DNS.timeout);
308 EV_DNS_LOGT_STOP(unwind_stack);
309 ev_idle_stop(event_base, &IO->unwind_stack);
312 void DestructCAres(AsyncIO *IO)
314 SetEVState(IO, eCaresX);
315 EVNC_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
317 EVNC_syslog(LOG_DEBUG, "C-ARES: - stopping %s %d %p \n", "DNS.recv_event", IO->DNS.recv_event.fd, &IO->DNS.recv_event);
318 ev_io_stop(event_base, &IO->DNS.recv_event);
320 EVNC_syslog(LOG_DEBUG, "C-ARES: - stopping %s %d %p\n", "DNS.send_event", IO->DNS.send_event.fd, &IO->DNS.send_event);
321 ev_io_stop(event_base, &IO->DNS.send_event);
323 EVNC_syslog(LOG_DEBUG, "C-ARES: - stopping %s %p\n", "DNS.timeout", &IO->DNS.send_event);
324 ev_timer_stop (event_base, &IO->DNS.timeout);
326 EVNC_syslog(LOG_DEBUG, "C-ARES: - stopping %s %p\n", "DNS.unwind_stack", &IO->unwind_stack);
327 ev_idle_stop(event_base, &IO->unwind_stack);
328 ares_destroy_options(&IO->DNS.Options);
332 void InitC_ares_dns(AsyncIO *IO)
336 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s %p\n", __FUNCTION__, IO->DNS.Channel);
338 if (IO->DNS.Channel == NULL) {
339 optmask |= ARES_OPT_SOCK_STATE_CB;
340 IO->DNS.Options.sock_state_cb = SockStateCb;
341 IO->DNS.Options.sock_state_cb_data = IO;
342 ares_init_options(&IO->DNS.Channel, &IO->DNS.Options, optmask);
344 IO->DNS.Query->DNSStatus = 0;
348 DNStimeouttrigger_callback(struct ev_loop *loop, ev_timer *watcher, int revents)
350 AsyncIO *IO = watcher->data;
351 struct timeval tv, MaxTV;
352 struct timeval *NextTV;
354 memset(&MaxTV, 0, sizeof(MaxTV));
355 memset(&tv, 0, sizeof(tv));
357 NextTV = ares_timeout(IO->DNS.Channel, &MaxTV, &tv);
359 if ((NextTV->tv_sec != MaxTV.tv_sec) ||
360 (NextTV->tv_usec != MaxTV.tv_usec))
362 fd_set readers, writers;
363 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s Timeout!\n", __FUNCTION__);
367 ares_fds(IO->DNS.Channel, &readers, &writers);
368 ares_process(IO->DNS.Channel, &readers, &writers);
372 void QueueGetHostByNameDone(void *Ctx,
375 struct hostent *hostent)
377 AsyncIO *IO = (AsyncIO *) Ctx;
379 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
382 IO->DNS.Query->DNSStatus = status;
383 IO->DNS.Query->VParsedDNSReply = hostent;
384 IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
386 EV_DNS_LOGT_STOP(DNS.timeout);
387 ev_timer_stop (event_base, &IO->DNS.timeout);
389 ev_idle_init(&IO->unwind_stack,
390 IO_postdns_callback);
391 IO->unwind_stack.data = IO;
392 EV_DNS_LOGT_INIT(unwind_stack);
393 EV_DNS_LOGT_START(unwind_stack);
394 ev_idle_start(event_base, &IO->unwind_stack);
398 void QueueGetHostByName(AsyncIO *IO,
399 const char *Hostname,
400 DNSQueryParts *QueryParts,
404 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
405 IO->DNS.SourcePort = 0;
407 IO->DNS.Query = QueryParts;
408 IO->DNS.Query->PostDNS = PostDNS;
412 ev_timer_init(&IO->DNS.timeout, DNStimeouttrigger_callback, 10, 1);
413 EV_DNS_LOGT_INIT(DNS.timeout);
414 IO->DNS.timeout.data = IO;
415 ares_gethostbyname(IO->DNS.Channel,
417 AF_INET6, /* it falls back to ipv4 in doubt... */
418 QueueGetHostByNameDone,
420 EV_DNS_LOGT_START(DNS.timeout);
421 ev_timer_start(event_base, &IO->DNS.timeout);
436 int QueueQuery(ns_type Type,
439 DNSQueryParts *QueryParts,
443 char address_b[sizeof(struct in6_addr)];
445 IO->DNS.SourcePort = 0;
447 IO->DNS.Query = QueryParts;
448 IO->DNS.Query->PostDNS = PostDNS;
449 IO->DNS.Start = IO->Now;
450 IO->DNS.Query->QStr = name;
454 ev_timer_init(&IO->DNS.timeout, DNStimeouttrigger_callback, 10, 1);
455 IO->DNS.timeout.data = IO;
456 EV_DNS_LOGT_INIT(DNS.timeout);
460 IO->DNS.Query->DNS_CB = ParseAnswerA;
461 IO->DNS.Query->QueryTYPE = QT[0];
465 IO->DNS.Query->DNS_CB = ParseAnswerAAAA;
466 IO->DNS.Query->QueryTYPE = QT[1];
470 IO->DNS.Query->DNS_CB = ParseAnswerMX;
471 IO->DNS.Query->QueryTYPE = QT[2];
475 IO->DNS.Query->DNS_CB = ParseAnswerNS;
476 IO->DNS.Query->QueryTYPE = QT[3];
480 IO->DNS.Query->DNS_CB = ParseAnswerTXT;
481 IO->DNS.Query->QueryTYPE = QT[4];
485 IO->DNS.Query->DNS_CB = ParseAnswerSRV;
486 IO->DNS.Query->QueryTYPE = QT[5];
490 IO->DNS.Query->DNS_CB = ParseAnswerCNAME;
491 IO->DNS.Query->QueryTYPE = QT[6];
495 IO->DNS.Query->QueryTYPE = QT[7];
496 if (inet_pton(AF_INET, name, &address_b) == 1) {
497 length = sizeof(struct in_addr);
499 } else if (inet_pton(AF_INET6, name, &address_b) == 1) {
500 length = sizeof(struct in6_addr);
506 ares_gethostbyaddr(IO->DNS.Channel,
512 EV_DNS_LOGT_START(DNS.timeout);
513 ev_timer_start(event_base, &IO->DNS.timeout);
515 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s X1\n", __FUNCTION__);
521 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %sX2\n", __FUNCTION__);
524 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
526 ares_query(IO->DNS.Channel, name, ns_c_in, Type, QueryCb, IO);
527 EV_DNS_LOGT_START(DNS.timeout);
528 ev_timer_start(event_base, &IO->DNS.timeout);
536 /*****************************************************************************
537 * libev / c-ares integration *
538 *****************************************************************************/
539 static void DNS_send_callback(struct ev_loop *loop, ev_io *watcher, int revents)
541 AsyncIO *IO = watcher->data;
543 IO->Now = ev_now(event_base);
545 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
547 ares_process_fd(IO->DNS.Channel,
549 IO->DNS.send_event.fd);
551 static void DNS_recv_callback(struct ev_loop *loop, ev_io *watcher, int revents)
553 AsyncIO *IO = watcher->data;
555 IO->Now = ev_now(event_base);
557 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
559 ares_process_fd(IO->DNS.Channel,
560 IO->DNS.recv_event.fd,
564 void SockStateCb(void *data, int sock, int read, int write)
567 /* already inside of the event queue. */
570 struct sockaddr_in sin;
572 memset(&sin, 0, sizeof(sin));
574 if ((IO->DNS.SourcePort == 0) &&
575 (getsockname(sock, &sin, &slen) == 0))
577 IO->DNS.SourcePort = ntohs(sin.sin_port);
579 EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s %d|%d Sock %d port %hu\n",
587 IO->Now = ev_now(event_base);
590 if ((IO->DNS.recv_event.fd != sock) &&
591 (IO->DNS.recv_event.fd != 0)) {
592 EV_DNS_LOG_STOP(DNS.recv_event);
593 ev_io_stop(event_base, &IO->DNS.recv_event);
595 IO->DNS.recv_event.fd = sock;
596 ev_io_init(&IO->DNS.recv_event,
598 IO->DNS.recv_event.fd,
600 EV_DNS_LOG_INIT(DNS.recv_event);
601 IO->DNS.recv_event.data = IO;
602 EV_DNS_LOG_START(DNS.recv_event);
603 ev_io_start(event_base, &IO->DNS.recv_event);
606 if ((IO->DNS.send_event.fd != sock) &&
607 (IO->DNS.send_event.fd != 0)) {
608 EV_DNS_LOG_STOP(DNS.send_event);
609 ev_io_stop(event_base, &IO->DNS.send_event);
611 IO->DNS.send_event.fd = sock;
612 ev_io_init(&IO->DNS.send_event,
614 IO->DNS.send_event.fd,
616 IO->DNS.send_event.data = IO;
617 EV_DNS_LOG_INIT(DNS.send_event);
618 EV_DNS_LOG_START(DNS.send_event);
619 ev_io_start(event_base, &IO->DNS.send_event);
621 if ((read == 0) && (write == 0)) {
622 EV_DNS_LOG_STOP(DNS.recv_event);
623 EV_DNS_LOG_STOP(DNS.send_event);
624 ev_io_stop(event_base, &IO->DNS.recv_event);
625 ev_io_stop(event_base, &IO->DNS.send_event);
628 void EnableDebugCAres(const int n)
633 CTDL_MODULE_INIT(c_ares_client)
637 CtdlRegisterDebugFlagHook(HKEY("cares"), EnableDebugCAres, &DebugCAres);
638 int r = ares_library_init(ARES_LIB_INIT_ALL);