C-Ares-DNS: when destructing make shure all events are stopped.
[citadel.git] / citadel / modules / c-ares-dns / serv_c-ares-dns.c
1 /*
2  * Copyright (c) 1998-2012 by the citadel.org team
3  *
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.
6  *  
7  *  
8  *
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.
13  *
14  *  
15  *  
16  *  
17  *
18  *  Inspired by NodeJS.org; thanks for the MX-Parser ;-)
19  */
20
21 #include "sysdep.h"
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <termios.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 #include <pwd.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 #include <syslog.h>
32
33 #if TIME_WITH_SYS_TIME
34 # include <sys/time.h>
35 # include <time.h>
36 #else
37 # if HAVE_SYS_TIME_H
38 #  include <sys/time.h>
39 # else
40 #  include <time.h>
41 # endif
42 #endif
43 #include <sys/wait.h>
44 #include <ctype.h>
45 #include <string.h>
46 #include <limits.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50
51 #include <libcitadel.h>
52 #include "citadel.h"
53 #include "server.h"
54 #include "citserver.h"
55 #include "support.h"
56
57 #include "ctdl_module.h"
58 #include "event_client.h"
59
60
61 extern struct ev_loop *event_base;
62
63 void SockStateCb(void *data, int sock, int read, int write);
64
65
66 static void HostByAddrCb(void *data,
67                          int status,
68                          int timeouts,
69                          struct hostent *hostent)
70 {
71         AsyncIO *IO = data;
72 #ifdef DEBUG_CARES
73         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
74         EV_DNS_LOGT_STOP(DNS.timeout);
75 #endif
76         ev_timer_stop (event_base, &IO->DNS.timeout);
77
78         IO->DNS.Query->DNSStatus = status;
79         if  (status != ARES_SUCCESS) {
80                 StrBufPlain(IO->ErrMsg, ares_strerror(status), -1);
81                 return;
82         }
83         IO->DNS.Query->Data = hostent;
84 }
85
86 static void ParseAnswerA(AsyncIO *IO, unsigned char* abuf, int alen)
87 {
88         struct hostent* host;
89 #ifdef DEBUG_CARES
90         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
91 #endif
92
93         if (IO->DNS.Query->VParsedDNSReply != NULL)
94                 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
95         IO->DNS.Query->VParsedDNSReply = NULL;
96
97         IO->DNS.Query->DNSStatus = ares_parse_a_reply(abuf,
98                                                       alen,
99                                                       &host,
100                                                       NULL,
101                                                       NULL);
102         if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
103                 StrBufPlain(IO->ErrMsg,
104                             ares_strerror(IO->DNS.Query->DNSStatus), -1);
105                 return;
106         }
107         IO->DNS.Query->VParsedDNSReply = host;
108         IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
109 }
110
111
112 static void ParseAnswerAAAA(AsyncIO *IO, unsigned char* abuf, int alen)
113 {
114         struct hostent* host;
115 #ifdef DEBUG_CARES
116         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
117 #endif
118
119         if (IO->DNS.Query->VParsedDNSReply != NULL)
120                 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
121         IO->DNS.Query->VParsedDNSReply = NULL;
122
123         IO->DNS.Query->DNSStatus = ares_parse_aaaa_reply(abuf,
124                                                          alen,
125                                                          &host,
126                                                          NULL,
127                                                          NULL);
128         if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
129                 StrBufPlain(IO->ErrMsg,
130                             ares_strerror(IO->DNS.Query->DNSStatus), -1);
131                 return;
132         }
133         IO->DNS.Query->VParsedDNSReply = host;
134         IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
135 }
136
137
138 static void ParseAnswerCNAME(AsyncIO *IO, unsigned char* abuf, int alen)
139 {
140         struct hostent* host;
141
142 #ifdef DEBUG_CARES
143         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
144 #endif
145
146         if (IO->DNS.Query->VParsedDNSReply != NULL)
147                 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
148         IO->DNS.Query->VParsedDNSReply = NULL;
149
150         IO->DNS.Query->DNSStatus = ares_parse_a_reply(abuf,
151                                                       alen,
152                                                       &host,
153                                                       NULL,
154                                                       NULL);
155         if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
156                 StrBufPlain(IO->ErrMsg,
157                             ares_strerror(IO->DNS.Query->DNSStatus), -1);
158                 return;
159         }
160
161         // a CNAME lookup always returns a single record but
162         IO->DNS.Query->VParsedDNSReply = host;
163         IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
164 }
165
166
167 static void ParseAnswerMX(AsyncIO *IO, unsigned char* abuf, int alen)
168 {
169         struct ares_mx_reply *mx_out;
170 #ifdef DEBUG_CARES
171         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
172 #endif
173
174         if (IO->DNS.Query->VParsedDNSReply != NULL)
175                 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
176         IO->DNS.Query->VParsedDNSReply = NULL;
177
178         IO->DNS.Query->DNSStatus = ares_parse_mx_reply(abuf, alen, &mx_out);
179         if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
180                 StrBufPlain(IO->ErrMsg,
181                             ares_strerror(IO->DNS.Query->DNSStatus), -1);
182                 return;
183         }
184
185         IO->DNS.Query->VParsedDNSReply = mx_out;
186         IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data;
187 }
188
189
190 static void ParseAnswerNS(AsyncIO *IO, unsigned char* abuf, int alen)
191 {
192         struct hostent* host;
193 #ifdef DEBUG_CARES
194         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
195 #endif
196
197         if (IO->DNS.Query->VParsedDNSReply != NULL)
198                 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
199         IO->DNS.Query->VParsedDNSReply = NULL;
200
201         IO->DNS.Query->DNSStatus = ares_parse_ns_reply(abuf, alen, &host);
202         if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
203                 StrBufPlain(IO->ErrMsg,
204                             ares_strerror(IO->DNS.Query->DNSStatus), -1);
205                 return;
206         }
207         IO->DNS.Query->VParsedDNSReply = host;
208         IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
209 }
210
211
212 static void ParseAnswerSRV(AsyncIO *IO, unsigned char* abuf, int alen)
213 {
214         struct ares_srv_reply *srv_out;
215 #ifdef DEBUG_CARES
216         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
217 #endif
218
219         if (IO->DNS.Query->VParsedDNSReply != NULL)
220                 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
221         IO->DNS.Query->VParsedDNSReply = NULL;
222
223         IO->DNS.Query->DNSStatus = ares_parse_srv_reply(abuf, alen, &srv_out);
224         if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
225                 StrBufPlain(IO->ErrMsg,
226                             ares_strerror(IO->DNS.Query->DNSStatus), -1);
227                 return;
228         }
229
230         IO->DNS.Query->VParsedDNSReply = srv_out;
231         IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data;
232 }
233
234
235 static void ParseAnswerTXT(AsyncIO *IO, unsigned char* abuf, int alen)
236 {
237         struct ares_txt_reply *txt_out;
238 #ifdef DEBUG_CARES
239         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
240 #endif
241
242         if (IO->DNS.Query->VParsedDNSReply != NULL)
243                 IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
244         IO->DNS.Query->VParsedDNSReply = NULL;
245
246         IO->DNS.Query->DNSStatus = ares_parse_txt_reply(abuf, alen, &txt_out);
247         if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
248                 StrBufPlain(IO->ErrMsg,
249                             ares_strerror(IO->DNS.Query->DNSStatus), -1);
250                 return;
251         }
252         IO->DNS.Query->VParsedDNSReply = txt_out;
253         IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data;
254 }
255
256 void QueryCb(void *arg,
257              int status,
258              int timeouts,
259              unsigned char* abuf,
260              int alen)
261 {
262         AsyncIO *IO = arg;
263 #ifdef DEBUG_CARES
264         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
265         EV_DNS_LOGT_STOP(DNS.timeout);
266 #endif
267         ev_timer_stop (event_base, &IO->DNS.timeout);
268
269         IO->DNS.Query->DNSStatus = status;
270         if (status == ARES_SUCCESS)
271                 IO->DNS.Query->DNS_CB(arg, abuf, alen);
272         else {
273                 EV_syslog(LOG_DEBUG, "C-ARES: Failed by: %s error %s\n",
274                           __FUNCTION__,
275                           ares_strerror(status));
276                 StrBufPlain(IO->ErrMsg, ares_strerror(status), -1);
277                 IO->DNS.Query->DNSStatus = status;
278         }
279
280         ev_idle_init(&IO->unwind_stack,
281                      IO_postdns_callback);
282         IO->unwind_stack.data = IO;
283         EV_DNS_LOGT_INIT(unwind_stack);
284         EV_DNS_LOGT_START(unwind_stack);
285         ev_idle_start(event_base, &IO->unwind_stack);
286 }
287
288 void QueryCbDone(AsyncIO *IO)
289 {
290 #ifdef DEBUG_CARES
291         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
292         EV_DNS_LOGT_STOP(DNS.timeout);
293 #endif
294
295         ev_idle_stop(event_base, &IO->unwind_stack);
296 }
297
298 void DestructCAres(AsyncIO *IO)
299 {
300 #ifdef DEBUG_CARES
301         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
302         EV_DNS_LOGT_STOP(DNS.timeout);
303 #endif
304         EV_DNS_LOG_STOP(DNS.recv_event);
305         ev_io_stop(event_base, &IO->DNS.recv_event);
306         EV_DNS_LOG_STOP(DNS.send_event);
307         ev_io_stop(event_base, &IO->DNS.send_event);
308         ev_timer_stop (event_base, &IO->DNS.timeout);
309         ev_idle_stop(event_base, &IO->unwind_stack);
310         ares_destroy_options(&IO->DNS.Options);
311 }
312
313
314 void InitC_ares_dns(AsyncIO *IO)
315 {
316         int optmask = 0;
317 #ifdef DEBUG_CARES
318         EV_syslog(LOG_DEBUG, "C-ARES: %s %p\n", __FUNCTION__, IO->DNS.Channel);
319 #endif
320
321         if (IO->DNS.Channel == NULL) {
322                 optmask |= ARES_OPT_SOCK_STATE_CB;
323                 IO->DNS.Options.sock_state_cb = SockStateCb;
324                 IO->DNS.Options.sock_state_cb_data = IO;
325                 ares_init_options(&IO->DNS.Channel, &IO->DNS.Options, optmask);
326         }
327         IO->DNS.Query->DNSStatus = 0;
328 }
329
330 static void
331 DNStimeouttrigger_callback(struct ev_loop *loop, ev_timer *watcher, int revents)
332 {
333         AsyncIO *IO = watcher->data;
334         struct timeval tv, MaxTV;
335         struct timeval *NextTV;
336
337         memset(&MaxTV, 0, sizeof(MaxTV));
338         memset(&tv, 0, sizeof(tv));
339         MaxTV.tv_sec = 30;
340         NextTV = ares_timeout(IO->DNS.Channel, &MaxTV, &tv);
341
342         if ((NextTV->tv_sec != MaxTV.tv_sec) ||
343             (NextTV->tv_usec != MaxTV.tv_usec))
344         {
345                 fd_set readers, writers;
346 #ifdef DEBUG_CARES
347                 EV_syslog(LOG_DEBUG, "C-ARES: %s Timeout!\n", __FUNCTION__);
348 #endif
349                 FD_ZERO(&readers);
350                 FD_ZERO(&writers);
351                 ares_fds(IO->DNS.Channel, &readers, &writers);
352                 ares_process(IO->DNS.Channel, &readers, &writers);
353         }
354 }
355
356 void QueueGetHostByNameDone(void *Ctx,
357                             int status,
358                             int timeouts,
359                             struct hostent *hostent)
360 {
361         AsyncIO *IO = (AsyncIO *) Ctx;
362 #ifdef DEBUG_CARES
363         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
364 #endif
365
366         IO->DNS.Query->DNSStatus = status;
367         IO->DNS.Query->VParsedDNSReply = hostent;
368         IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
369
370         ev_idle_init(&IO->unwind_stack,
371                      IO_postdns_callback);
372         IO->unwind_stack.data = IO;
373         EV_DNS_LOGT_INIT(unwind_stack);
374         EV_DNS_LOGT_START(unwind_stack);
375         ev_idle_start(event_base, &IO->unwind_stack);
376         ev_timer_stop (event_base, &IO->DNS.timeout);
377 }
378
379 void QueueGetHostByName(AsyncIO *IO,
380                         const char *Hostname,
381                         DNSQueryParts *QueryParts,
382                         IO_CallBack PostDNS)
383 {
384 #ifdef DEBUG_CARES
385         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
386         IO->DNS.SourcePort = 0;
387 #endif
388
389         IO->DNS.Query = QueryParts;
390         IO->DNS.Query->PostDNS = PostDNS;
391
392         InitC_ares_dns(IO);
393
394         ev_timer_init(&IO->DNS.timeout, DNStimeouttrigger_callback, 10, 1);
395         EV_DNS_LOGT_INIT(DNS.timeout);
396         IO->DNS.timeout.data = IO;
397         ares_gethostbyname(IO->DNS.Channel,
398                            Hostname,
399                            AF_INET6, /* it falls back to ipv4 in doubt... */
400                            QueueGetHostByNameDone,
401                            IO);
402         EV_DNS_LOGT_START(DNS.timeout);
403         ev_timer_start(event_base, &IO->DNS.timeout);
404
405 }
406
407 int QueueQuery(ns_type Type,
408                const char *name,
409                AsyncIO *IO,
410                DNSQueryParts *QueryParts,
411                IO_CallBack PostDNS)
412 {
413         int length, family;
414         char address_b[sizeof(struct in6_addr)];
415
416 #ifdef DEBUG_CARES
417         IO->DNS.SourcePort = 0;
418 #endif
419
420         IO->DNS.Query = QueryParts;
421         IO->DNS.Query->PostDNS = PostDNS;
422
423         InitC_ares_dns(IO);
424
425         ev_timer_init(&IO->DNS.timeout, DNStimeouttrigger_callback, 10, 1);
426         IO->DNS.timeout.data = IO;
427         EV_DNS_LOGT_INIT(DNS.timeout);
428
429         switch(Type) {
430         case ns_t_a:
431                 IO->DNS.Query->DNS_CB = ParseAnswerA;
432                 break;
433
434         case ns_t_aaaa:
435                 IO->DNS.Query->DNS_CB = ParseAnswerAAAA;
436                 break;
437
438         case ns_t_mx:
439                 IO->DNS.Query->DNS_CB = ParseAnswerMX;
440                 break;
441
442         case ns_t_ns:
443                 IO->DNS.Query->DNS_CB = ParseAnswerNS;
444                 break;
445
446         case ns_t_txt:
447                 IO->DNS.Query->DNS_CB = ParseAnswerTXT;
448                 break;
449
450         case ns_t_srv:
451                 IO->DNS.Query->DNS_CB = ParseAnswerSRV;
452                 break;
453
454         case ns_t_cname:
455                 IO->DNS.Query->DNS_CB = ParseAnswerCNAME;
456                 break;
457
458         case ns_t_ptr:
459
460
461                 if (inet_pton(AF_INET, name, &address_b) == 1) {
462                         length = sizeof(struct in_addr);
463                         family = AF_INET;
464                 } else if (inet_pton(AF_INET6, name, &address_b) == 1) {
465                         length = sizeof(struct in6_addr);
466                         family = AF_INET6;
467                 } else {
468                         return -1;
469                 }
470
471                 ares_gethostbyaddr(IO->DNS.Channel,
472                                    address_b,
473                                    length,
474                                    family,
475                                    HostByAddrCb,
476                                    IO);
477                 EV_DNS_LOGT_START(DNS.timeout);
478                 ev_timer_start(event_base, &IO->DNS.timeout);
479 #ifdef DEBUG_CARES
480                 EV_syslog(LOG_DEBUG, "C-ARES: %s X1\n", __FUNCTION__);
481 #endif
482                 return 1;
483
484         default:
485 #ifdef DEBUG_CARES
486                 EV_syslog(LOG_DEBUG, "C-ARES: %sX2\n", __FUNCTION__);
487 #endif
488                 return 0;
489         }
490 #ifdef DEBUG_CARES
491         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
492 #endif
493         ares_query(IO->DNS.Channel, name, ns_c_in, Type, QueryCb, IO);
494         EV_DNS_LOGT_START(DNS.timeout);
495         ev_timer_start(event_base, &IO->DNS.timeout);
496         return 1;
497 }
498
499
500
501
502
503 /*****************************************************************************
504  *                      libev / c-ares integration                           *
505  *****************************************************************************/
506 static void DNS_send_callback(struct ev_loop *loop, ev_io *watcher, int revents)
507 {
508         AsyncIO *IO = watcher->data;
509
510 #ifdef DEBUG_CARES
511         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
512 #endif
513
514         ares_process_fd(IO->DNS.Channel,
515                         ARES_SOCKET_BAD,
516                         IO->DNS.send_event.fd);
517 }
518 static void DNS_recv_callback(struct ev_loop *loop, ev_io *watcher, int revents)
519 {
520         AsyncIO *IO = watcher->data;
521
522 #ifdef DEBUG_CARES
523         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
524 #endif
525
526         ares_process_fd(IO->DNS.Channel,
527                         IO->DNS.recv_event.fd,
528                         ARES_SOCKET_BAD);
529 }
530
531 void SockStateCb(void *data, int sock, int read, int write)
532 {
533         AsyncIO *IO = data;
534 /* already inside of the event queue. */
535 #ifdef DEBUG_CARES
536 {
537         struct sockaddr_in sin = {};
538         socklen_t slen;
539         slen = sizeof(sin);
540         if ((IO->DNS.SourcePort == 0) &&
541             (getsockname(sock, &sin, &slen) == 0))
542         {
543                 IO->DNS.SourcePort = ntohs(sin.sin_port);
544         }
545         EV_syslog(LOG_DEBUG, "C-ARES: %s %d|%d Sock %d port %hu\n",
546                   __FUNCTION__,
547                   read,
548                   write,
549                   sock,
550                   IO->DNS.SourcePort);
551 }
552 #endif
553
554         if (read) {
555                 if ((IO->DNS.recv_event.fd != sock) &&
556                     (IO->DNS.recv_event.fd != 0)) {
557                         EV_DNS_LOG_STOP(DNS.recv_event);
558                         ev_io_stop(event_base, &IO->DNS.recv_event);
559                 }
560                 IO->DNS.recv_event.fd = sock;
561                 ev_io_init(&IO->DNS.recv_event,
562                            DNS_recv_callback,
563                            IO->DNS.recv_event.fd,
564                            EV_READ);
565                 EV_DNS_LOG_INIT(DNS.recv_event);
566                 IO->DNS.recv_event.data = IO;
567                 EV_DNS_LOG_START(DNS.recv_event);
568                 ev_io_start(event_base, &IO->DNS.recv_event);
569         }
570         if (write) {
571                 if ((IO->DNS.send_event.fd != sock) &&
572                     (IO->DNS.send_event.fd != 0)) {
573                         EV_DNS_LOG_STOP(DNS.send_event);
574                         ev_io_stop(event_base, &IO->DNS.send_event);
575                 }
576                 IO->DNS.send_event.fd = sock;
577                 ev_io_init(&IO->DNS.send_event,
578                            DNS_send_callback,
579                            IO->DNS.send_event.fd,
580                            EV_WRITE);
581                 IO->DNS.send_event.data = IO;
582                 EV_DNS_LOG_INIT(DNS.send_event);
583                 EV_DNS_LOG_START(DNS.send_event);
584                 ev_io_start(event_base, &IO->DNS.send_event);
585         }
586         if ((read == 0) && (write == 0)) {
587                 EV_DNS_LOG_STOP(DNS.recv_event);
588                 EV_DNS_LOG_STOP(DNS.send_event);
589                 ev_io_stop(event_base, &IO->DNS.recv_event);
590                 ev_io_stop(event_base, &IO->DNS.send_event);
591         }
592 }
593
594 CTDL_MODULE_INIT(c_ares_client)
595 {
596         if (!threading)
597         {
598                 int r = ares_library_init(ARES_LIB_INIT_ALL);
599                 if (0 != r) {
600                         
601                 }
602         }
603         return "c-ares";
604 }