glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / dns / dnsstub.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2018 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14 */
15 /**
16  * @file dns/dnsstub.c
17  * @brief DNS stub resolver which sends DNS requests to an actual resolver
18  * @author Christian Grothoff
19  */
20 #include "platform.h"
21 #include "gnunet_util_lib.h"
22 #include "gnunet_tun_lib.h"
23 #include "gnunet_dnsstub_lib.h"
24
25 /**
26  * Timeout for retrying DNS queries.
27  */
28 #define DNS_RETRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
29
30
31 /**
32  * DNS Server used for resolution.
33  */
34 struct DnsServer;
35
36
37 /**
38  * UDP socket we are using for sending DNS requests to the Internet.
39  */
40 struct GNUNET_DNSSTUB_RequestSocket
41 {
42
43   /**
44    * UDP socket we use for this request for IPv4
45    */
46   struct GNUNET_NETWORK_Handle *dnsout4;
47
48   /**
49    * UDP socket we use for this request for IPv6
50    */
51   struct GNUNET_NETWORK_Handle *dnsout6;
52
53   /**
54    * Function to call with result.
55    */
56   GNUNET_DNSSTUB_ResultCallback rc;
57
58   /**
59    * Closure for @e rc.
60    */
61   void *rc_cls;
62
63   /**
64    * Task for reading from dnsout4 and dnsout6.
65    */
66   struct GNUNET_SCHEDULER_Task *read_task;
67
68   /**
69    * Task for retrying transmission of the query.
70    */
71   struct GNUNET_SCHEDULER_Task *retry_task;
72
73   /**
74    * Next address we sent the DNS request to.
75    */
76   struct DnsServer *ds_pos;
77
78   /**
79    * Context this request executes in.
80    */
81   struct GNUNET_DNSSTUB_Context *ctx;
82
83   /**
84    * Query we sent to @e addr.
85    */
86   void *request;
87
88   /**
89    * Number of bytes in @a request.
90    */
91   size_t request_len;
92
93 };
94
95
96 /**
97  * DNS Server used for resolution.
98  */
99 struct DnsServer
100 {
101
102   /**
103    * Kept in a DLL.
104    */
105   struct DnsServer *next;
106
107   /**
108    * Kept in a DLL.
109    */
110   struct DnsServer *prev;
111
112   /**
113    * IP address of the DNS resolver.
114    */
115   struct sockaddr_storage ss;
116 };
117
118
119 /**
120  * Handle to the stub resolver.
121  */
122 struct GNUNET_DNSSTUB_Context
123 {
124
125   /**
126    * Array of all open sockets for DNS requests.
127    */
128   struct GNUNET_DNSSTUB_RequestSocket *sockets;
129
130   /**
131    * DLL of DNS resolvers we use.
132    */
133   struct DnsServer *dns_head;
134
135   /**
136    * DLL of DNS resolvers we use.
137    */
138   struct DnsServer *dns_tail;
139
140   /**
141    * How frequently do we retry requests?
142    */
143   struct GNUNET_TIME_Relative retry_freq;
144
145   /**
146    * Length of @e sockets array.
147    */
148   unsigned int num_sockets;
149
150 };
151
152
153 /**
154  * We're done with a `struct GNUNET_DNSSTUB_RequestSocket`, close it for now.
155  *
156  * @param rs request socket to clean up
157  */
158 static void
159 cleanup_rs (struct GNUNET_DNSSTUB_RequestSocket *rs)
160 {
161   if (NULL != rs->dnsout4)
162   {
163     GNUNET_NETWORK_socket_close (rs->dnsout4);
164     rs->dnsout4 = NULL;
165   }
166   if (NULL != rs->dnsout6)
167   {
168     GNUNET_NETWORK_socket_close (rs->dnsout6);
169     rs->dnsout6 = NULL;
170   }
171   if (NULL != rs->read_task)
172   {
173     GNUNET_SCHEDULER_cancel (rs->read_task);
174     rs->read_task = NULL;
175   }
176   if (NULL != rs->retry_task)
177   {
178     GNUNET_SCHEDULER_cancel (rs->retry_task);
179     rs->retry_task = NULL;
180   }
181   if (NULL != rs->request)
182   {
183     GNUNET_free (rs->request);
184     rs->request = NULL;
185   }
186 }
187
188
189 /**
190  * Open source port for sending DNS requests
191  *
192  * @param af AF_INET or AF_INET6
193  * @return #GNUNET_OK on success
194  */
195 static struct GNUNET_NETWORK_Handle *
196 open_socket (int af)
197 {
198   struct sockaddr_in a4;
199   struct sockaddr_in6 a6;
200   struct sockaddr *sa;
201   socklen_t alen;
202   struct GNUNET_NETWORK_Handle *ret;
203
204   ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0);
205   if (NULL == ret)
206     return NULL;
207   switch (af)
208   {
209   case AF_INET:
210     memset (&a4, 0, alen = sizeof (struct sockaddr_in));
211     sa = (struct sockaddr *) &a4;
212     break;
213   case AF_INET6:
214     memset (&a6, 0, alen = sizeof (struct sockaddr_in6));
215     sa = (struct sockaddr *) &a6;
216     break;
217   default:
218     GNUNET_break (0);
219     GNUNET_NETWORK_socket_close (ret);
220     return NULL;
221   }
222   sa->sa_family = af;
223   if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret,
224                                                sa,
225                                                alen))
226   {
227     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
228                 _("Could not bind to any port: %s\n"),
229                 STRERROR (errno));
230     GNUNET_NETWORK_socket_close (ret);
231     return NULL;
232   }
233   return ret;
234 }
235
236
237 /**
238  * Get a socket of the specified address family to send out a
239  * UDP DNS request to the Internet.
240  *
241  * @param ctx the DNSSTUB context
242  * @return NULL on error
243  */
244 static struct GNUNET_DNSSTUB_RequestSocket *
245 get_request_socket (struct GNUNET_DNSSTUB_Context *ctx)
246 {
247   struct GNUNET_DNSSTUB_RequestSocket *rs;
248
249   for (unsigned int i=0;i<256;i++)
250   {
251     rs = &ctx->sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
252                                                  ctx->num_sockets)];
253     if (NULL == rs->rc)
254       break;
255   }
256   if (NULL != rs->rc)
257   {
258     /* signal "failure" */
259     rs->rc (rs->rc_cls,
260             NULL,
261             0);
262     rs->rc = NULL;
263   }
264   if (NULL != rs->read_task)
265   {
266     GNUNET_SCHEDULER_cancel (rs->read_task);
267     rs->read_task = NULL;
268   }
269   if (NULL != rs->retry_task)
270   {
271     GNUNET_SCHEDULER_cancel (rs->retry_task);
272     rs->retry_task = NULL;
273   }
274   if (NULL != rs->request)
275   {
276     GNUNET_free (rs->request);
277     rs->request = NULL;
278   }
279   rs->ctx = ctx;
280   return rs;
281 }
282
283
284 /**
285  * Actually do the reading of a DNS packet from our UDP socket and see
286  * if we have a valid, matching, pending request.
287  *
288  * @param rs request socket with callback details
289  * @param dnsout socket to read from
290  * @return #GNUNET_OK on success, #GNUNET_NO on drop, #GNUNET_SYSERR on IO-errors (closed socket)
291  */
292 static int
293 do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
294              struct GNUNET_NETWORK_Handle *dnsout)
295 {
296   struct GNUNET_DNSSTUB_Context *ctx = rs->ctx;
297   ssize_t r;
298   int len;
299
300 #ifndef MINGW
301   if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout),
302                   FIONREAD,
303                   &len))
304   {
305     /* conservative choice: */
306     len = UINT16_MAX;
307   }
308 #else
309   /* port the code above? */
310   len = UINT16_MAX;
311 #endif
312   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
313               "Receiving %d byte DNS reply\n",
314               len);
315   {
316     unsigned char buf[len] GNUNET_ALIGN;
317     int found;
318     struct sockaddr_storage addr;
319     socklen_t addrlen;
320     struct GNUNET_TUN_DnsHeader *dns;
321
322     addrlen = sizeof (addr);
323     memset (&addr,
324             0,
325             sizeof (addr));
326     r = GNUNET_NETWORK_socket_recvfrom (dnsout,
327                                         buf,
328                                         sizeof (buf),
329                                         (struct sockaddr*) &addr,
330                                         &addrlen);
331     if (-1 == r)
332     {
333       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
334                            "recvfrom");
335       GNUNET_NETWORK_socket_close (dnsout);
336       return GNUNET_SYSERR;
337     }
338     found = GNUNET_NO;
339     for (struct DnsServer *ds = ctx->dns_head; NULL != ds; ds = ds->next)
340     {
341       if (0 == memcmp (&addr,
342                        &ds->ss,
343                        GNUNET_MIN (sizeof (struct sockaddr_storage),
344                                    addrlen)))
345       {
346         found = GNUNET_YES;
347         break;
348       }
349     }
350     if (GNUNET_NO == found)
351     {
352       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
353                   "Received DNS response from server we never asked (ignored)");
354       return GNUNET_NO;
355     }
356     if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
357     {
358       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
359                   _("Received DNS response that is too small (%u bytes)"),
360                   (unsigned int) r);
361       return GNUNET_NO;
362     }
363     dns = (struct GNUNET_TUN_DnsHeader *) buf;
364     if (NULL == rs->rc)
365     {
366       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
367                   "Request timeout or cancelled; ignoring reply\n");
368       return GNUNET_NO;
369     }
370     rs->rc (rs->rc_cls,
371             dns,
372             r);
373   }
374   return GNUNET_OK;
375 }
376
377
378 /**
379  * Read a DNS response from the (unhindered) UDP-Socket
380  *
381  * @param cls socket to read from
382  */
383 static void
384 read_response (void *cls);
385
386
387 /**
388  * Schedule #read_response() task for @a rs.
389  *
390  * @param rs request to schedule read operation for
391  */
392 static void
393 schedule_read (struct GNUNET_DNSSTUB_RequestSocket *rs)
394 {
395   struct GNUNET_NETWORK_FDSet *rset;
396
397   if (NULL != rs->read_task)
398     GNUNET_SCHEDULER_cancel (rs->read_task);
399   rset = GNUNET_NETWORK_fdset_create ();
400   if (NULL != rs->dnsout4)
401     GNUNET_NETWORK_fdset_set (rset,
402                               rs->dnsout4);
403   if (NULL != rs->dnsout6)
404     GNUNET_NETWORK_fdset_set (rset,
405                               rs->dnsout6);
406   rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
407                                                GNUNET_TIME_UNIT_FOREVER_REL,
408                                                rset,
409                                                NULL,
410                                                &read_response,
411                                                rs);
412   GNUNET_NETWORK_fdset_destroy (rset);
413 }
414
415
416 /**
417  * Read a DNS response from the (unhindered) UDP-Socket
418  *
419  * @param cls `struct GNUNET_DNSSTUB_RequestSocket` to read from
420  */
421 static void
422 read_response (void *cls)
423 {
424   struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
425   const struct GNUNET_SCHEDULER_TaskContext *tc;
426
427   rs->read_task = NULL;
428   tc = GNUNET_SCHEDULER_get_task_context ();
429   /* read and process ready sockets */
430   if ( (NULL != rs->dnsout4) &&
431        (GNUNET_NETWORK_fdset_isset (tc->read_ready,
432                                     rs->dnsout4)) &&
433        (GNUNET_SYSERR ==
434         do_dns_read (rs,
435                      rs->dnsout4)) )
436     rs->dnsout4 = NULL;
437   if ( (NULL != rs->dnsout6) &&
438        (GNUNET_NETWORK_fdset_isset (tc->read_ready,
439                                     rs->dnsout6)) &&
440        (GNUNET_SYSERR ==
441         do_dns_read (rs,
442                      rs->dnsout6)) )
443     rs->dnsout6 = NULL;
444   /* re-schedule read task */
445   schedule_read (rs);
446 }
447
448
449 /**
450  * Task to (re)transmit the DNS query, possibly repeatedly until
451  * we succeed.
452  *
453  * @param cls our `struct GNUNET_DNSSTUB_RequestSocket *`
454  */
455 static void
456 transmit_query (void *cls)
457 {
458   struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
459   struct GNUNET_DNSSTUB_Context *ctx = rs->ctx;
460   const struct sockaddr *sa;
461   socklen_t salen;
462   struct DnsServer *ds;
463   struct GNUNET_NETWORK_Handle *dnsout;
464
465   rs->retry_task = GNUNET_SCHEDULER_add_delayed (ctx->retry_freq,
466                                                  &transmit_query,
467                                                  rs);
468   ds = rs->ds_pos;
469   rs->ds_pos = ds->next;
470   if (NULL == rs->ds_pos)
471     rs->ds_pos = ctx->dns_head;
472   GNUNET_assert (NULL != ds);
473   dnsout = NULL;
474   switch (ds->ss.ss_family)
475   {
476   case AF_INET:
477     if (NULL == rs->dnsout4)
478       rs->dnsout4 = open_socket (AF_INET);
479     dnsout = rs->dnsout4;
480     sa = (const struct sockaddr *) &ds->ss;
481     salen = sizeof (struct sockaddr_in);
482     break;
483   case AF_INET6:
484     if (NULL == rs->dnsout6)
485       rs->dnsout6 = open_socket (AF_INET6);
486     dnsout = rs->dnsout6;
487     sa = (const struct sockaddr *) &ds->ss;
488     salen = sizeof (struct sockaddr_in6);
489     break;
490   default:
491     return;
492   }
493   if (NULL == dnsout)
494   {
495     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
496                 "Unable to use configure DNS server, skipping\n");
497     return;
498   }
499   if (GNUNET_SYSERR ==
500       GNUNET_NETWORK_socket_sendto (dnsout,
501                                     rs->request,
502                                     rs->request_len,
503                                     sa,
504                                     salen))
505     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
506                 _("Failed to send DNS request to %s: %s\n"),
507                 GNUNET_a2s (sa,
508                             salen),
509                 STRERROR (errno));
510   else
511     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
512                 _("Sent DNS request to %s\n"),
513                 GNUNET_a2s (sa,
514                             salen));
515   schedule_read (rs);
516 }
517
518
519 /**
520  * Perform DNS resolution using our default IP from init.
521  *
522  * @param ctx stub resolver to use
523  * @param request DNS request to transmit
524  * @param request_len number of bytes in msg
525  * @param rc function to call with result
526  * @param rc_cls closure for 'rc'
527  * @return socket used for the request, NULL on error
528  */
529 struct GNUNET_DNSSTUB_RequestSocket *
530 GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx,
531                          const void *request,
532                          size_t request_len,
533                          GNUNET_DNSSTUB_ResultCallback rc,
534                          void *rc_cls)
535 {
536   struct GNUNET_DNSSTUB_RequestSocket *rs;
537
538   if (NULL == ctx->dns_head)
539   {
540     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
541                 "No DNS server configured for resolution\n");
542     return NULL;
543   }
544   if (NULL == (rs = get_request_socket (ctx)))
545   {
546     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
547                 "No request socket available for DNS resolution\n");
548     return NULL;
549   }
550   rs->ds_pos = ctx->dns_head;
551   rs->rc = rc;
552   rs->rc_cls = rc_cls;
553   rs->request = GNUNET_memdup (request,
554                                request_len);
555   rs->request_len = request_len;
556   rs->retry_task = GNUNET_SCHEDULER_add_now (&transmit_query,
557                                              rs);
558   return rs;
559 }
560
561
562 /**
563  * Cancel DNS resolution.
564  *
565  * @param rs resolution to cancel
566  */
567 void
568 GNUNET_DNSSTUB_resolve_cancel (struct GNUNET_DNSSTUB_RequestSocket *rs)
569 {
570   rs->rc = NULL;
571   if (NULL != rs->retry_task)
572   {
573     GNUNET_SCHEDULER_cancel (rs->retry_task);
574     rs->retry_task = NULL;
575   }
576   if (NULL != rs->read_task)
577   {
578     GNUNET_SCHEDULER_cancel (rs->read_task);
579     rs->read_task = NULL;
580   }
581 }
582
583
584 /**
585  * Start a DNS stub resolver.
586  *
587  * @param num_sockets how many sockets should we open
588  *        in parallel for DNS queries for this stub?
589  * @return NULL on error
590  */
591 struct GNUNET_DNSSTUB_Context *
592 GNUNET_DNSSTUB_start (unsigned int num_sockets)
593 {
594   struct GNUNET_DNSSTUB_Context *ctx;
595
596   if (0 == num_sockets)
597   {
598     GNUNET_break (0);
599     return NULL;
600   }
601   ctx = GNUNET_new (struct GNUNET_DNSSTUB_Context);
602   ctx->num_sockets = num_sockets;
603   ctx->sockets = GNUNET_new_array (num_sockets,
604                                    struct GNUNET_DNSSTUB_RequestSocket);
605   ctx->retry_freq = DNS_RETRANSMIT_DELAY;
606   return ctx;
607 }
608
609
610 /**
611  * Add nameserver for use by the DNSSTUB.  We will use
612  * all provided nameservers for resolution (round-robin).
613  *
614  * @param ctx resolver context to modify
615  * @param dns_ip target IP address to use (as string)
616  * @return #GNUNET_OK on success
617  */
618 int
619 GNUNET_DNSSTUB_add_dns_ip (struct GNUNET_DNSSTUB_Context *ctx,
620                            const char *dns_ip)
621 {
622   struct DnsServer *ds;
623   struct in_addr i4;
624   struct in6_addr i6;
625
626   ds = GNUNET_new (struct DnsServer);
627   if (1 == inet_pton (AF_INET,
628                       dns_ip,
629                       &i4))
630   {
631     struct sockaddr_in *s4 = (struct sockaddr_in *) &ds->ss;
632
633     s4->sin_family = AF_INET;
634     s4->sin_port = htons (53);
635     s4->sin_addr = i4;
636 #if HAVE_SOCKADDR_IN_SIN_LEN
637     s4->sin_len = (u_char) sizeof (struct sockaddr_in);
638 #endif
639   }
640   else if (1 == inet_pton (AF_INET6,
641                            dns_ip,
642                            &i6))
643   {
644     struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &ds->ss;
645
646     s6->sin6_family = AF_INET6;
647     s6->sin6_port = htons (53);
648     s6->sin6_addr = i6;
649 #if HAVE_SOCKADDR_IN_SIN_LEN
650     s6->sin6_len = (u_char) sizeof (struct sockaddr_in6);
651 #endif
652   }
653   else
654   {
655     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
656                 "Malformed IP address `%s' for DNS server\n",
657                 dns_ip);
658     GNUNET_free (ds);
659     return GNUNET_SYSERR;
660   }
661   GNUNET_CONTAINER_DLL_insert (ctx->dns_head,
662                                ctx->dns_tail,
663                                ds);
664   return GNUNET_OK;
665 }
666
667
668 /**
669  * Add nameserver for use by the DNSSTUB.  We will use
670  * all provided nameservers for resolution (round-robin).
671  *
672  * @param ctx resolver context to modify
673  * @param sa socket address of DNS resolver to use
674  * @return #GNUNET_OK on success
675  */
676 int
677 GNUNET_DNSSTUB_add_dns_sa (struct GNUNET_DNSSTUB_Context *ctx,
678                            const struct sockaddr *sa)
679 {
680   struct DnsServer *ds;
681
682   ds = GNUNET_new (struct DnsServer);
683   switch (sa->sa_family)
684   {
685   case AF_INET:
686     GNUNET_memcpy (&ds->ss,
687                    sa,
688                    sizeof (struct sockaddr_in));
689     break;
690   case AF_INET6:
691     GNUNET_memcpy (&ds->ss,
692                    sa,
693                    sizeof (struct sockaddr_in6));
694     break;
695   default:
696     GNUNET_break (0);
697     GNUNET_free (ds);
698     return GNUNET_SYSERR;
699   }
700   GNUNET_CONTAINER_DLL_insert (ctx->dns_head,
701                                ctx->dns_tail,
702                                ds);
703   return GNUNET_OK;
704 }
705
706
707 /**
708  * How long should we try requests before timing out?
709  * Only effective for requests issued after this call.
710  *
711  * @param ctx resolver context to modify
712  * @param retry_freq how long to wait between retries
713  */
714 void
715 GNUNET_DNSSTUB_set_retry (struct GNUNET_DNSSTUB_Context *ctx,
716                           struct GNUNET_TIME_Relative retry_freq)
717 {
718   ctx->retry_freq = retry_freq;
719 }
720
721
722 /**
723  * Cleanup DNSSTUB resolver.
724  *
725  * @param ctx stub resolver to clean up
726  */
727 void
728 GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx)
729 {
730   struct DnsServer *ds;
731
732   while (NULL != (ds = ctx->dns_head))
733   {
734     GNUNET_CONTAINER_DLL_remove (ctx->dns_head,
735                                  ctx->dns_tail,
736                                  ds);
737     GNUNET_free (ds);
738   }
739   for (unsigned int i=0;i<ctx->num_sockets;i++)
740     cleanup_rs (&ctx->sockets[i]);
741   GNUNET_free (ctx->sockets);
742   GNUNET_free (ctx);
743 }
744
745
746 /* end of dnsstub.c */