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