d1b1a027e5f86d2ac33acdad19115058585d4b69
[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         IO->DNS.Start = IO->Now;
437
438         InitC_ares_dns(IO);
439
440         ev_timer_init(&IO->DNS.timeout, DNStimeouttrigger_callback, 10, 1);
441         IO->DNS.timeout.data = IO;
442         EV_DNS_LOGT_INIT(DNS.timeout);
443
444         switch(Type) {
445         case ns_t_a:
446                 IO->DNS.Query->DNS_CB = ParseAnswerA;
447                 break;
448
449         case ns_t_aaaa:
450                 IO->DNS.Query->DNS_CB = ParseAnswerAAAA;
451                 break;
452
453         case ns_t_mx:
454                 IO->DNS.Query->DNS_CB = ParseAnswerMX;
455                 break;
456
457         case ns_t_ns:
458                 IO->DNS.Query->DNS_CB = ParseAnswerNS;
459                 break;
460
461         case ns_t_txt:
462                 IO->DNS.Query->DNS_CB = ParseAnswerTXT;
463                 break;
464
465         case ns_t_srv:
466                 IO->DNS.Query->DNS_CB = ParseAnswerSRV;
467                 break;
468
469         case ns_t_cname:
470                 IO->DNS.Query->DNS_CB = ParseAnswerCNAME;
471                 break;
472
473         case ns_t_ptr:
474
475
476                 if (inet_pton(AF_INET, name, &address_b) == 1) {
477                         length = sizeof(struct in_addr);
478                         family = AF_INET;
479                 } else if (inet_pton(AF_INET6, name, &address_b) == 1) {
480                         length = sizeof(struct in6_addr);
481                         family = AF_INET6;
482                 } else {
483                         return -1;
484                 }
485
486                 ares_gethostbyaddr(IO->DNS.Channel,
487                                    address_b,
488                                    length,
489                                    family,
490                                    HostByAddrCb,
491                                    IO);
492                 EV_DNS_LOGT_START(DNS.timeout);
493                 ev_timer_start(event_base, &IO->DNS.timeout);
494 #ifdef DEBUG_CARES
495                 EV_syslog(LOG_DEBUG, "C-ARES: %s X1\n", __FUNCTION__);
496 #endif
497                 return 1;
498
499         default:
500 #ifdef DEBUG_CARES
501                 EV_syslog(LOG_DEBUG, "C-ARES: %sX2\n", __FUNCTION__);
502 #endif
503                 return 0;
504         }
505 #ifdef DEBUG_CARES
506         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
507 #endif
508         ares_query(IO->DNS.Channel, name, ns_c_in, Type, QueryCb, IO);
509         EV_DNS_LOGT_START(DNS.timeout);
510         ev_timer_start(event_base, &IO->DNS.timeout);
511         return 1;
512 }
513
514
515
516
517
518 /*****************************************************************************
519  *                      libev / c-ares integration                           *
520  *****************************************************************************/
521 static void DNS_send_callback(struct ev_loop *loop, ev_io *watcher, int revents)
522 {
523         AsyncIO *IO = watcher->data;
524
525         IO->Now = ev_now(event_base);
526 #ifdef DEBUG_CARES
527         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
528 #endif
529
530         ares_process_fd(IO->DNS.Channel,
531                         ARES_SOCKET_BAD,
532                         IO->DNS.send_event.fd);
533 }
534 static void DNS_recv_callback(struct ev_loop *loop, ev_io *watcher, int revents)
535 {
536         AsyncIO *IO = watcher->data;
537
538         IO->Now = ev_now(event_base);
539
540 #ifdef DEBUG_CARES
541         EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
542 #endif
543
544         ares_process_fd(IO->DNS.Channel,
545                         IO->DNS.recv_event.fd,
546                         ARES_SOCKET_BAD);
547 }
548
549 void SockStateCb(void *data, int sock, int read, int write)
550 {
551         AsyncIO *IO = data;
552 /* already inside of the event queue. */
553 #ifdef DEBUG_CARES
554 {
555         struct sockaddr_in sin = {};
556         socklen_t slen;
557         slen = sizeof(sin);
558         if ((IO->DNS.SourcePort == 0) &&
559             (getsockname(sock, &sin, &slen) == 0))
560         {
561                 IO->DNS.SourcePort = ntohs(sin.sin_port);
562         }
563         EV_syslog(LOG_DEBUG, "C-ARES: %s %d|%d Sock %d port %hu\n",
564                   __FUNCTION__,
565                   read,
566                   write,
567                   sock,
568                   IO->DNS.SourcePort);
569 }
570 #endif
571         IO->Now = ev_now(event_base);
572
573         if (read) {
574                 if ((IO->DNS.recv_event.fd != sock) &&
575                     (IO->DNS.recv_event.fd != 0)) {
576                         EV_DNS_LOG_STOP(DNS.recv_event);
577                         ev_io_stop(event_base, &IO->DNS.recv_event);
578                 }
579                 IO->DNS.recv_event.fd = sock;
580                 ev_io_init(&IO->DNS.recv_event,
581                            DNS_recv_callback,
582                            IO->DNS.recv_event.fd,
583                            EV_READ);
584                 EV_DNS_LOG_INIT(DNS.recv_event);
585                 IO->DNS.recv_event.data = IO;
586                 EV_DNS_LOG_START(DNS.recv_event);
587                 ev_io_start(event_base, &IO->DNS.recv_event);
588         }
589         if (write) {
590                 if ((IO->DNS.send_event.fd != sock) &&
591                     (IO->DNS.send_event.fd != 0)) {
592                         EV_DNS_LOG_STOP(DNS.send_event);
593                         ev_io_stop(event_base, &IO->DNS.send_event);
594                 }
595                 IO->DNS.send_event.fd = sock;
596                 ev_io_init(&IO->DNS.send_event,
597                            DNS_send_callback,
598                            IO->DNS.send_event.fd,
599                            EV_WRITE);
600                 IO->DNS.send_event.data = IO;
601                 EV_DNS_LOG_INIT(DNS.send_event);
602                 EV_DNS_LOG_START(DNS.send_event);
603                 ev_io_start(event_base, &IO->DNS.send_event);
604         }
605         if ((read == 0) && (write == 0)) {
606                 EV_DNS_LOG_STOP(DNS.recv_event);
607                 EV_DNS_LOG_STOP(DNS.send_event);
608                 ev_io_stop(event_base, &IO->DNS.recv_event);
609                 ev_io_stop(event_base, &IO->DNS.send_event);
610         }
611 }
612
613 CTDL_MODULE_INIT(c_ares_client)
614 {
615         if (!threading)
616         {
617                 int r = ares_library_init(ARES_LIB_INIT_ALL);
618                 if (0 != r) {
619                         
620                 }
621         }
622         return "c-ares";
623 }