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