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