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