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