Merge branch 'master' of ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / pt / gnunet-daemon-pt.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010, 2012, 2017 Christian Grothoff
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 pt/gnunet-daemon-pt.c
22  * @brief tool to manipulate DNS and VPN services to perform protocol translation (IPvX over GNUnet)
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_dns_service.h"
28 #include "gnunet_dnsparser_lib.h"
29 #include "gnunet_cadet_service.h"
30 #include "gnunet_tun_lib.h"
31 #include "gnunet_dht_service.h"
32 #include "gnunet_vpn_service.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_applications.h"
35 #include "block_dns.h"
36
37
38 /**
39  * After how long do we time out if we could not get an IP from VPN or CADET?
40  */
41 #define TIMEOUT GNUNET_TIME_UNIT_MINUTES
42
43 /**
44  * How many bytes of payload do we allow at most for a DNS reply?
45  * Given that this is pretty much limited to loopback, we can be
46  * pretty high (Linux loopback defaults to 16k, most local UDP packets
47  * should survive up to 9k (NFS), so 8k should be pretty safe in
48  * general).
49  */
50 #define MAX_DNS_SIZE (8 * 1024)
51
52 /**
53  * How many channels do we open at most at the same time?
54  */
55 #define MAX_OPEN_TUNNELS 4
56
57
58 /**
59  * Which group of DNS records are we currently processing?
60  */
61 enum RequestGroup
62 {
63   /**
64    * DNS answers
65    */
66   ANSWERS = 0,
67
68   /**
69    * DNS authority records
70    */
71   AUTHORITY_RECORDS = 1,
72
73   /**
74    * DNS additional records
75    */
76   ADDITIONAL_RECORDS = 2,
77
78   /**
79    * We're done processing.
80    */
81   END = 3
82 };
83
84
85 /**
86  * Information tracked per DNS reply that we are processing.
87  */
88 struct ReplyContext
89 {
90   /**
91    * Handle to submit the final result.
92    */
93   struct GNUNET_DNS_RequestHandle *rh;
94
95   /**
96    * DNS packet that is being modified.
97    */
98   struct GNUNET_DNSPARSER_Packet *dns;
99
100   /**
101    * Active redirection request with the VPN.
102    */
103   struct GNUNET_VPN_RedirectionRequest *rr;
104
105   /**
106    * Record for which we have an active redirection request.
107    */
108   struct GNUNET_DNSPARSER_Record *rec;
109
110   /**
111    * Offset in the current record group that is being modified.
112    */
113   unsigned int offset;
114
115   /**
116    * Group that is being modified
117    */
118   enum RequestGroup group;
119
120 };
121
122
123 /**
124  * Handle to a peer that advertised that it is willing to serve
125  * as a DNS exit.  We try to keep a few channels open and a few
126  * peers in reserve.
127  */
128 struct CadetExit
129 {
130
131   /**
132    * Kept in a DLL.
133    */
134   struct CadetExit *next;
135
136   /**
137    * Kept in a DLL.
138    */
139   struct CadetExit *prev;
140
141   /**
142    * Channel we use for DNS requests over CADET, NULL if we did
143    * not initialze a channel to this peer yet.
144    */
145   struct GNUNET_CADET_Channel *cadet_channel;
146
147   /**
148    * At what time did the peer's advertisement expire?
149    */
150   struct GNUNET_TIME_Absolute expiration;
151
152   /**
153    * Head of DLL of requests waiting for a response.
154    */
155   struct RequestContext *receive_queue_head;
156
157   /**
158    * Tail of DLL of requests waiting for a response.
159    */
160   struct RequestContext *receive_queue_tail;
161
162   /**
163    * Identity of the peer that is providing the exit for us.
164    */
165   struct GNUNET_PeerIdentity peer;
166
167   /**
168    * How many DNS requests did we transmit via this channel?
169    */
170   unsigned int num_transmitted;
171
172   /**
173    * How many DNS requests were answered via this channel?
174    */
175   unsigned int num_answered;
176
177   /**
178    * Size of the window, 0 if we are busy.
179    */
180   /* unsigned */ int idle;
181
182 };
183
184
185
186 /**
187  * State we keep for a request that is going out via CADET.
188  */
189 struct RequestContext
190 {
191   /**
192    * We keep these in a DLL.
193    */
194   struct RequestContext *next;
195
196   /**
197    * We keep these in a DLL.
198    */
199   struct RequestContext *prev;
200
201   /**
202    * Exit that was chosen for this request.
203    */
204   struct CadetExit *exit;
205
206   /**
207    * Handle for interaction with DNS service.
208    */
209   struct GNUNET_DNS_RequestHandle *rh;
210
211   /**
212    * Envelope with the request we are transmitting.
213    */
214   struct GNUNET_MQ_Envelope *env;
215
216   /**
217    * Task used to abort this operation with timeout.
218    */
219   struct GNUNET_SCHEDULER_Task *timeout_task;
220
221   /**
222    * Length of the request message that follows this struct.
223    */
224   uint16_t mlen;
225
226   /**
227    * ID of the original DNS request (used to match the reply).
228    */
229   uint16_t dns_id;
230
231 };
232
233
234 /**
235  * Head of DLL of cadet exits.  Cadet exits with an open channel are
236  * always at the beginning (so we do not have to traverse the entire
237  * list to find them).
238  */
239 static struct CadetExit *exit_head;
240
241 /**
242  * Tail of DLL of cadet exits.
243  */
244 static struct CadetExit *exit_tail;
245
246 /**
247  * The handle to the configuration used throughout the process
248  */
249 static const struct GNUNET_CONFIGURATION_Handle *cfg;
250
251 /**
252  * The handle to the VPN
253  */
254 static struct GNUNET_VPN_Handle *vpn_handle;
255
256 /**
257  * The handle to the CADET service
258  */
259 static struct GNUNET_CADET_Handle *cadet_handle;
260
261 /**
262  * Statistics.
263  */
264 static struct GNUNET_STATISTICS_Handle *stats;
265
266 /**
267  * The handle to DNS post-resolution modifications.
268  */
269 static struct GNUNET_DNS_Handle *dns_post_handle;
270
271 /**
272  * The handle to DNS pre-resolution modifications.
273  */
274 static struct GNUNET_DNS_Handle *dns_pre_handle;
275
276 /**
277  * Handle to access the DHT.
278  */
279 static struct GNUNET_DHT_Handle *dht;
280
281 /**
282  * Our DHT GET operation to find DNS exits.
283  */
284 static struct GNUNET_DHT_GetHandle *dht_get;
285
286 /**
287  * Are we doing IPv4-pt?
288  */
289 static int ipv4_pt;
290
291 /**
292  * Are we doing IPv6-pt?
293  */
294 static int ipv6_pt;
295
296 /**
297  * Are we channeling DNS queries?
298  */
299 static int dns_channel;
300
301 /**
302  * Number of DNS exit peers we currently have in the cadet channel.
303  * Used to see if using the cadet channel makes any sense right now,
304  * as well as to decide if we should open new channels.
305  */
306 static unsigned int dns_exit_available;
307
308
309 /**
310  * We are short on cadet exits, try to open another one.
311  */
312 static void
313 try_open_exit (void);
314
315
316 /**
317  * Compute the weight of the given exit.  The higher the weight,
318  * the more likely it will be that the channel will be chosen.
319  * A weigt of zero means that we should close the channel as it
320  * is so bad, that we should not use it.
321  *
322  * @param exit exit to calculate the weight for
323  * @return weight of the channel
324  */
325 static uint32_t
326 get_channel_weight (struct CadetExit *exit)
327 {
328   uint32_t dropped;
329   uint32_t drop_percent;
330   uint32_t good_percent;
331
332   GNUNET_assert (exit->num_transmitted >= exit->num_answered);
333   dropped = exit->num_transmitted - exit->num_answered;
334   if (exit->num_transmitted > 0)
335     drop_percent = (uint32_t) ((100LL * dropped) / exit->num_transmitted);
336   else
337     drop_percent = 50; /* no data */
338   if ( (exit->num_transmitted > 20) &&
339        (drop_percent > 25) )
340     return 0; /* statistically significant, and > 25% loss, die */
341   good_percent = 100 - drop_percent;
342   GNUNET_assert (0 != good_percent);
343   if ( UINT32_MAX / good_percent / good_percent < exit->num_transmitted)
344     return UINT32_MAX; /* formula below would overflow */
345   return 1 + good_percent * good_percent * exit->num_transmitted;
346 }
347
348
349 /**
350  * Choose a cadet exit for a DNS request.  We try to use a channel
351  * that is reliable and currently available.  All existing
352  * channels are given a base weight of 1, plus a score relating
353  * to the total number of queries answered in relation to the
354  * total number of queries we sent to that channel.  That
355  * score is doubled if the channel is currently idle.
356  *
357  * @return NULL if no exit is known, otherwise the
358  *         exit that we should use to queue a message with
359  */
360 static struct CadetExit *
361 choose_exit ()
362 {
363   struct CadetExit *pos;
364   uint64_t total_transmitted;
365   uint64_t selected_offset;
366   uint32_t channel_weight;
367
368   total_transmitted = 0;
369   for (pos = exit_head; NULL != pos; pos = pos->next)
370   {
371     if (NULL == pos->cadet_channel)
372       break;
373     channel_weight = get_channel_weight (pos);
374     total_transmitted += channel_weight;
375     /* double weight for idle channels */
376     if (0 != pos->idle)
377       total_transmitted += channel_weight;
378   }
379   if (0 == total_transmitted)
380   {
381     /* no channels available, or only a very bad one... */
382     return exit_head;
383   }
384   selected_offset = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
385                                               total_transmitted);
386   total_transmitted = 0;
387   for (pos = exit_head; NULL != pos; pos = pos->next)
388   {
389     if (NULL == pos->cadet_channel)
390       break;
391     channel_weight = get_channel_weight (pos);
392     total_transmitted += channel_weight;
393     /* double weight for idle channels */
394     if (0 != pos->idle)
395       total_transmitted += channel_weight;
396     if (total_transmitted > selected_offset)
397       return pos;
398   }
399   GNUNET_break (0);
400   return NULL;
401 }
402
403
404 /**
405  * We're done modifying all records in the response.  Submit the reply
406  * and free the resources of the rc.
407  *
408  * @param rc context to process
409  */
410 static void
411 finish_request (struct ReplyContext *rc)
412 {
413   char *buf;
414   size_t buf_len;
415
416   if (GNUNET_SYSERR ==
417       GNUNET_DNSPARSER_pack (rc->dns,
418                              MAX_DNS_SIZE,
419                              &buf,
420                              &buf_len))
421   {
422     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
423                 _("Failed to pack DNS request.  Dropping.\n"));
424     GNUNET_DNS_request_drop (rc->rh);
425   }
426   else
427   {
428     GNUNET_STATISTICS_update (stats,
429                               gettext_noop ("# DNS requests mapped to VPN"),
430                               1, GNUNET_NO);
431     GNUNET_DNS_request_answer (rc->rh,
432                                buf_len,
433                                buf);
434     GNUNET_free (buf);
435   }
436   GNUNET_DNSPARSER_free_packet (rc->dns);
437   GNUNET_free (rc);
438 }
439
440
441 /**
442  * Process the next record of the given request context.
443  * When done, submit the reply and free the resources of
444  * the rc.
445  *
446  * @param rc context to process
447  */
448 static void
449 submit_request (struct ReplyContext *rc);
450
451
452 /**
453  * Callback invoked from the VPN service once a redirection is
454  * available.  Provides the IP address that can now be used to
455  * reach the requested destination.  We substitute the active
456  * record and then continue with 'submit_request' to look at
457  * the other records.
458  *
459  * @param cls our `struct ReplyContext`
460  * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
461  *                will match 'result_af' from the request
462  * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
463  *                that the VPN allocated for the redirection;
464  *                traffic to this IP will now be redirected to the
465  *                specified target peer; NULL on error
466  */
467 static void
468 vpn_allocation_callback (void *cls,
469                          int af,
470                          const void *address)
471 {
472   struct ReplyContext *rc = cls;
473
474   rc->rr = NULL;
475   if (af == AF_UNSPEC)
476   {
477     GNUNET_DNS_request_drop (rc->rh);
478     GNUNET_DNSPARSER_free_packet (rc->dns);
479     GNUNET_free (rc);
480     return;
481   }
482   GNUNET_STATISTICS_update (stats,
483                             gettext_noop ("# DNS records modified"),
484                             1,
485                             GNUNET_NO);
486   switch (rc->rec->type)
487   {
488   case GNUNET_DNSPARSER_TYPE_A:
489     GNUNET_assert (AF_INET == af);
490     GNUNET_memcpy (rc->rec->data.raw.data,
491                    address,
492                    sizeof (struct in_addr));
493     break;
494   case GNUNET_DNSPARSER_TYPE_AAAA:
495     GNUNET_assert (AF_INET6 == af);
496     GNUNET_memcpy (rc->rec->data.raw.data,
497                    address,
498                    sizeof (struct in6_addr));
499     break;
500   default:
501     GNUNET_assert (0);
502     return;
503   }
504   rc->rec = NULL;
505   submit_request (rc);
506 }
507
508
509 /**
510  * Modify the given DNS record by asking VPN to create a channel
511  * to the given address.  When done, continue with submitting
512  * other records from the request context ('submit_request' is
513  * our continuation).
514  *
515  * @param rc context to process
516  * @param rec record to modify
517  */
518 static void
519 modify_address (struct ReplyContext *rc,
520                 struct GNUNET_DNSPARSER_Record *rec)
521 {
522   int af;
523
524   switch (rec->type)
525   {
526   case GNUNET_DNSPARSER_TYPE_A:
527     af = AF_INET;
528     GNUNET_assert (rec->data.raw.data_len == sizeof (struct in_addr));
529     break;
530   case GNUNET_DNSPARSER_TYPE_AAAA:
531     af = AF_INET6;
532     GNUNET_assert (rec->data.raw.data_len == sizeof (struct in6_addr));
533     break;
534   default:
535     GNUNET_assert (0);
536     return;
537   }
538   rc->rec = rec;
539   rc->rr = GNUNET_VPN_redirect_to_ip (vpn_handle,
540                                       af,
541                                       af,
542                                       rec->data.raw.data,
543                                       GNUNET_TIME_relative_to_absolute (TIMEOUT),
544                                       &vpn_allocation_callback,
545                                       rc);
546 }
547
548
549 /**
550  * Process the next record of the given request context.
551  * When done, submit the reply and free the resources of
552  * the rc.
553  *
554  * @param rc context to process
555  */
556 static void
557 submit_request (struct ReplyContext *rc)
558 {
559   struct GNUNET_DNSPARSER_Record *ra;
560   unsigned int ra_len;
561   unsigned int i;
562
563   while (1)
564   {
565     switch (rc->group)
566     {
567     case ANSWERS:
568       ra = rc->dns->answers;
569       ra_len = rc->dns->num_answers;
570       break;
571     case AUTHORITY_RECORDS:
572       ra = rc->dns->authority_records;
573       ra_len = rc->dns->num_authority_records;
574       break;
575     case ADDITIONAL_RECORDS:
576       ra = rc->dns->additional_records;
577       ra_len = rc->dns->num_additional_records;
578       break;
579     case END:
580       finish_request (rc);
581       return;
582     default:
583       GNUNET_assert (0);
584     }
585     for (i=rc->offset;i<ra_len;i++)
586     {
587       switch (ra[i].type)
588       {
589       case GNUNET_DNSPARSER_TYPE_A:
590         if (ipv4_pt)
591         {
592           rc->offset = i + 1;
593           modify_address (rc,
594                           &ra[i]);
595           return;
596         }
597         break;
598       case GNUNET_DNSPARSER_TYPE_AAAA:
599         if (ipv6_pt)
600         {
601           rc->offset = i + 1;
602           modify_address (rc,
603                           &ra[i]);
604           return;
605         }
606         break;
607       }
608     }
609     rc->group++;
610   }
611 }
612
613
614 /**
615  * Test if any of the given records need protocol-translation work.
616  *
617  * @param ra array of records
618  * @param ra_len number of entries in @a ra
619  * @return #GNUNET_YES if any of the given records require protocol-translation
620  */
621 static int
622 work_test (const struct GNUNET_DNSPARSER_Record *ra,
623            unsigned int ra_len)
624 {
625   unsigned int i;
626
627   for (i=0;i<ra_len;i++)
628   {
629     switch (ra[i].type)
630     {
631     case GNUNET_DNSPARSER_TYPE_A:
632       if (ipv4_pt)
633         return GNUNET_YES;
634       break;
635     case GNUNET_DNSPARSER_TYPE_AAAA:
636       if (ipv6_pt)
637         return GNUNET_YES;
638       break;
639     }
640   }
641   return GNUNET_NO;
642 }
643
644
645 /**
646  * This function is called AFTER we got an IP address for a
647  * DNS request.  Now, the PT daemon has the chance to substitute
648  * the IP address with one from the VPN range to channel requests
649  * destined for this IP address via VPN and CADET.
650  *
651  * @param cls closure
652  * @param rh request handle to user for reply
653  * @param request_length number of bytes in request
654  * @param request udp payload of the DNS request
655  */
656 static void
657 dns_post_request_handler (void *cls,
658                           struct GNUNET_DNS_RequestHandle *rh,
659                           size_t request_length,
660                           const char *request)
661 {
662   struct GNUNET_DNSPARSER_Packet *dns;
663   struct ReplyContext *rc;
664   int work;
665
666   GNUNET_STATISTICS_update (stats,
667                             gettext_noop ("# DNS replies intercepted"),
668                             1, GNUNET_NO);
669   dns = GNUNET_DNSPARSER_parse (request,
670                                 request_length);
671   if (NULL == dns)
672   {
673     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
674                 _("Failed to parse DNS request.  Dropping.\n"));
675     GNUNET_DNS_request_drop (rh);
676     return;
677   }
678   work = GNUNET_NO;
679   work |= work_test (dns->answers,
680                      dns->num_answers);
681   work |= work_test (dns->authority_records,
682                      dns->num_authority_records);
683   work |= work_test (dns->additional_records,
684                      dns->num_additional_records);
685   if (! work)
686   {
687     GNUNET_DNS_request_forward (rh);
688     GNUNET_DNSPARSER_free_packet (dns);
689     return;
690   }
691   rc = GNUNET_new (struct ReplyContext);
692   rc->rh = rh;
693   rc->dns = dns;
694   rc->offset = 0;
695   rc->group = ANSWERS;
696   submit_request (rc);
697 }
698
699
700 /**
701  * Task run if the time to answer a DNS request via CADET is over.
702  *
703  * @param cls the `struct RequestContext` to abort
704  */
705 static void
706 timeout_request (void *cls)
707 {
708   struct RequestContext *rc = cls;
709   struct CadetExit *exit = rc->exit;
710
711   GNUNET_STATISTICS_update (stats,
712                             gettext_noop ("# DNS requests dropped (timeout)"),
713                             1,
714                             GNUNET_NO);
715   GNUNET_DNS_request_drop (rc->rh);
716   GNUNET_free (rc);
717   if ( (0 == get_channel_weight (exit)) &&
718        (NULL == exit->receive_queue_head) )
719   {
720     /* this straw broke the camel's back: this channel now has
721        such a low score that it will not be used; close it! */
722     GNUNET_CADET_channel_destroy (exit->cadet_channel);
723     exit->cadet_channel = NULL;
724     GNUNET_CONTAINER_DLL_remove (exit_head,
725                                  exit_tail,
726                                  exit);
727     GNUNET_CONTAINER_DLL_insert_tail (exit_head,
728                                       exit_tail,
729                                       exit);
730     /* go back to semi-innocent: mark as not great, but
731        avoid a prohibitively negative score (see
732        #get_channel_weight(), which checks for a certain
733        minimum number of transmissions before making
734        up an opinion) */
735     exit->num_transmitted = 5;
736     exit->num_answered = 0;
737     dns_exit_available--;
738     /* now try to open an alternative exit */
739     try_open_exit ();
740   }
741 }
742
743
744 /**
745  * This function is called *before* the DNS request has been
746  * given to a "local" DNS resolver.  Channeling for DNS requests
747  * was enabled, so we now need to send the request via some CADET
748  * channel to a DNS EXIT for resolution.
749  *
750  * @param cls closure
751  * @param rh request handle to user for reply
752  * @param request_length number of bytes in request
753  * @param request udp payload of the DNS request
754  */
755 static void
756 dns_pre_request_handler (void *cls,
757                          struct GNUNET_DNS_RequestHandle *rh,
758                          size_t request_length,
759                          const char *request)
760 {
761   struct RequestContext *rc;
762   struct GNUNET_MQ_Envelope *env;
763   struct GNUNET_MessageHeader *hdr;
764   struct GNUNET_TUN_DnsHeader dns;
765   struct CadetExit *exit;
766
767   GNUNET_STATISTICS_update (stats,
768                             gettext_noop ("# DNS requests intercepted"),
769                             1, GNUNET_NO);
770   if (0 == dns_exit_available)
771   {
772     GNUNET_STATISTICS_update (stats,
773                               gettext_noop ("# DNS requests dropped (DNS cadet channel down)"),
774                               1, GNUNET_NO);
775     GNUNET_DNS_request_drop (rh);
776     return;
777   }
778   if (request_length < sizeof (dns))
779   {
780     GNUNET_STATISTICS_update (stats,
781                               gettext_noop ("# DNS requests dropped (malformed)"),
782                               1, GNUNET_NO);
783     GNUNET_DNS_request_drop (rh);
784     return;
785   }
786   exit = choose_exit ();
787   GNUNET_assert (NULL != exit);
788   GNUNET_assert (NULL != exit->cadet_channel);
789
790   env = GNUNET_MQ_msg_extra (hdr,
791                              request_length,
792                              GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET);
793   GNUNET_memcpy (&hdr[1],
794                  request,
795                  request_length);
796   rc = GNUNET_new (struct RequestContext);
797   rc->exit = exit;
798   rc->rh = rh;
799   rc->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
800                                                    &timeout_request,
801                                                    rc);
802   GNUNET_memcpy (&dns,
803                  request,
804                  sizeof (dns));
805   rc->dns_id = dns.id;
806   rc->env = env;
807   GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
808                                exit->receive_queue_tail,
809                                rc);
810   if (0 < exit->idle)
811     exit->idle--;
812   exit->num_transmitted++;
813   GNUNET_MQ_send (GNUNET_CADET_get_mq (exit->cadet_channel),
814                   GNUNET_MQ_env_copy (env));
815 }
816
817
818 GNUNET_NETWORK_STRUCT_BEGIN
819
820 /**
821  * Message with a DNS response.
822  */
823 struct DnsResponseMessage
824 {
825   /**
826    * GNUnet header, of type #GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET
827    */
828   struct GNUNET_MessageHeader header;
829
830   /**
831    * DNS header.
832    */
833   struct GNUNET_TUN_DnsHeader dns;
834
835   /* Followed by more DNS payload */
836 };
837
838 GNUNET_NETWORK_STRUCT_END
839
840 /**
841  * Process a request via cadet to perform a DNS query.
842  *
843  * @param cls the `struct CadetExit` which got the message
844  * @param msg the actual message
845  * @return #GNUNET_OK to keep the connection open,
846  *         #GNUNET_SYSERR to close it (signal serious error)
847  */
848 static int
849 check_dns_response (void *cls,
850                      const struct DnsResponseMessage *msg)
851 {
852   return GNUNET_OK; /* all OK */
853 }
854
855
856 /**
857  * Process a request via cadet to perform a DNS query.
858  *
859  * @param cls the `struct CadetExit` which got the message
860  * @param msg the actual message
861  */
862 static void
863 handle_dns_response (void *cls,
864                      const struct DnsResponseMessage *msg)
865 {
866   struct CadetExit *exit = cls;
867   size_t mlen;
868   struct RequestContext *rc;
869
870   mlen = ntohs (msg->header.size) - sizeof (*msg);
871   for (rc = exit->receive_queue_head; NULL != rc; rc = rc->next)
872   {
873     if (msg->dns.id == rc->dns_id)
874     {
875       GNUNET_STATISTICS_update (stats,
876                                 gettext_noop ("# DNS replies received"),
877                                 1,
878                                 GNUNET_NO);
879       GNUNET_DNS_request_answer (rc->rh,
880                                  mlen + sizeof (struct GNUNET_TUN_DnsHeader),
881                                  (const void*) &msg->dns);
882       GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
883                                    exit->receive_queue_tail,
884                                    rc);
885       GNUNET_SCHEDULER_cancel (rc->timeout_task);
886       GNUNET_MQ_discard (rc->env);
887       GNUNET_free (rc);
888       exit->num_answered++;
889       return;
890     }
891   }
892   GNUNET_STATISTICS_update (stats,
893                             gettext_noop ("# DNS replies dropped (too late?)"),
894                             1, GNUNET_NO);
895 }
896
897
898 /**
899  * Abort all pending DNS requests with the given cadet exit.
900  *
901  * @param exit cadet exit to abort requests for
902  */
903 static void
904 abort_all_requests (struct CadetExit *exit)
905 {
906   struct RequestContext *rc;
907
908   while (NULL != (rc = exit->receive_queue_head))
909   {
910     GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
911                                  exit->receive_queue_tail,
912                                  rc);
913     GNUNET_DNS_request_drop (rc->rh);
914     GNUNET_SCHEDULER_cancel (rc->timeout_task);
915     GNUNET_MQ_discard (rc->env);
916     GNUNET_free (rc);
917   }
918 }
919
920
921 /**
922  * Function scheduled as very last function, cleans up after us
923  *
924  * @param cls closure, NULL
925  */
926 static void
927 cleanup (void *cls)
928 {
929   struct CadetExit *exit;
930
931   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
932               "Protocol translation daemon is shutting down now\n");
933   if (NULL != vpn_handle)
934   {
935     GNUNET_VPN_disconnect (vpn_handle);
936     vpn_handle = NULL;
937   }
938   while (NULL != (exit = exit_head))
939   {
940     GNUNET_CONTAINER_DLL_remove (exit_head,
941                                  exit_tail,
942                                  exit);
943     if (NULL != exit->cadet_channel)
944     {
945       GNUNET_CADET_channel_destroy (exit->cadet_channel);
946       exit->cadet_channel = NULL;
947     }
948     abort_all_requests (exit);
949     GNUNET_free (exit);
950   }
951   if (NULL != cadet_handle)
952   {
953     GNUNET_CADET_disconnect (cadet_handle);
954     cadet_handle = NULL;
955   }
956   if (NULL != dns_post_handle)
957   {
958     GNUNET_DNS_disconnect (dns_post_handle);
959     dns_post_handle = NULL;
960   }
961   if (NULL != dns_pre_handle)
962   {
963     GNUNET_DNS_disconnect (dns_pre_handle);
964     dns_pre_handle = NULL;
965   }
966   if (NULL != stats)
967   {
968     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
969     stats = NULL;
970   }
971   if (NULL != dht_get)
972   {
973     GNUNET_DHT_get_stop (dht_get);
974     dht_get = NULL;
975   }
976   if (NULL != dht)
977   {
978     GNUNET_DHT_disconnect (dht);
979     dht = NULL;
980   }
981 }
982
983
984 /**
985  * Function called whenever a channel is destroyed.  Should clean up
986  * the associated state and attempt to build a new one.
987  *
988  * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
989  *
990  * @param cls closure (the `struct CadetExit` set from #GNUNET_CADET_connect)
991  * @param channel connection to the other end (henceforth invalid)
992  * @param channel_ctx place where local state associated
993  *                   with the channel is stored
994  */
995 static void
996 cadet_channel_end_cb (void *cls,
997                       const struct GNUNET_CADET_Channel *channel)
998 {
999   struct CadetExit *exit = cls;
1000   struct CadetExit *alt;
1001   struct RequestContext *rc;
1002
1003   exit->cadet_channel = NULL;
1004   dns_exit_available--;
1005   /* open alternative channels */
1006   /* our channel is now closed, move our requests to an alternative
1007      channel */
1008   alt = choose_exit ();
1009   while (NULL != (rc = exit->receive_queue_head))
1010   {
1011     GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1012                                  exit->receive_queue_tail,
1013                                  rc);
1014     rc->exit = alt;
1015     GNUNET_CONTAINER_DLL_insert (alt->receive_queue_head,
1016                                  alt->receive_queue_tail,
1017                                  rc);
1018     GNUNET_MQ_send (GNUNET_CADET_get_mq (exit->cadet_channel),
1019                     GNUNET_MQ_env_copy (rc->env));
1020   }
1021   try_open_exit ();
1022 }
1023
1024
1025 /**
1026  * Function called whenever a channel has excess capacity.
1027  *
1028  * @param cls the `struct CadetExit`
1029  * @param channel connection to the other end
1030  * @param window_size how much capacity do we have
1031  */
1032 static void
1033 channel_idle_notify_cb (void *cls,
1034                         const struct GNUNET_CADET_Channel *channel,
1035                         int window_size)
1036 {
1037   struct CadetExit *pos = cls;
1038
1039   pos->idle = window_size;
1040 }
1041
1042
1043 /**
1044  * We are short on cadet exits, try to open another one.
1045  */
1046 static void
1047 try_open_exit ()
1048 {
1049   struct CadetExit *pos;
1050   uint32_t candidate_count;
1051   uint32_t candidate_selected;
1052   struct GNUNET_HashCode port;
1053
1054   GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER,
1055                       strlen (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER),
1056                       &port);
1057   candidate_count = 0;
1058   for (pos = exit_head; NULL != pos; pos = pos->next)
1059     if (NULL == pos->cadet_channel)
1060       candidate_count++;
1061   if (0 == candidate_count)
1062   {
1063     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1064                 "No DNS exits available yet.\n");
1065     return;
1066   }
1067   candidate_selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1068                                                  candidate_count);
1069   candidate_count = 0;
1070   for (pos = exit_head; NULL != pos; pos = pos->next)
1071     if (NULL == pos->cadet_channel)
1072     {
1073       candidate_count++;
1074       if (candidate_selected < candidate_count)
1075       {
1076         struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1077           GNUNET_MQ_hd_var_size (dns_response,
1078                                  GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET,
1079                                  struct DnsResponseMessage,
1080                                  pos),
1081           GNUNET_MQ_handler_end ()
1082         };
1083
1084
1085         /* move to the head of the DLL */
1086         pos->cadet_channel
1087           = GNUNET_CADET_channel_creatE (cadet_handle,
1088                                          pos,
1089                                          &pos->peer,
1090                                          &port,
1091                                          GNUNET_CADET_OPTION_DEFAULT,
1092                                          &channel_idle_notify_cb,
1093                                          &cadet_channel_end_cb,
1094                                          cadet_handlers);
1095         if (NULL == pos->cadet_channel)
1096         {
1097           GNUNET_break (0);
1098           continue;
1099         }
1100         GNUNET_CONTAINER_DLL_remove (exit_head,
1101                                      exit_tail,
1102                                      pos);
1103         GNUNET_CONTAINER_DLL_insert (exit_head,
1104                                      exit_tail,
1105                                      pos);
1106         dns_exit_available++;
1107         return;
1108       }
1109     }
1110   GNUNET_assert (NULL == exit_head);
1111 }
1112
1113
1114 /**
1115  * Function called whenever we find an advertisement for a
1116  * DNS exit in the DHT.  If we don't have a cadet channel,
1117  * we should build one; otherwise, we should save the
1118  * advertisement for later use.
1119  *
1120  * @param cls closure
1121  * @param exp when will this value expire
1122  * @param key key of the result
1123  * @param get_path peers on reply path (or NULL if not recorded)
1124  *                 [0] = datastore's first neighbor, [length - 1] = local peer
1125  * @param get_path_length number of entries in @a get_path
1126  * @param put_path peers on the PUT path (or NULL if not recorded)
1127  *                 [0] = origin, [length - 1] = datastore
1128  * @param put_path_length number of entries in @a put_path
1129  * @param type type of the result
1130  * @param size number of bytes in @a data
1131  * @param data pointer to the result data
1132  */
1133 static void
1134 handle_dht_result (void *cls,
1135                    struct GNUNET_TIME_Absolute exp,
1136                    const struct GNUNET_HashCode *key,
1137                    const struct GNUNET_PeerIdentity *get_path,
1138                    unsigned int get_path_length,
1139                    const struct GNUNET_PeerIdentity *put_path,
1140                    unsigned int put_path_length,
1141                    enum GNUNET_BLOCK_Type type,
1142                    size_t size, const void *data)
1143 {
1144   const struct GNUNET_DNS_Advertisement *ad;
1145   struct CadetExit *exit;
1146
1147   if (sizeof (struct GNUNET_DNS_Advertisement) != size)
1148   {
1149     GNUNET_break (0);
1150     return;
1151   }
1152   ad = data;
1153   for (exit = exit_head; NULL != exit; exit = exit->next)
1154     if (0 == memcmp (&ad->peer,
1155                      &exit->peer,
1156                      sizeof (struct GNUNET_PeerIdentity)))
1157       break;
1158   if (NULL == exit)
1159   {
1160     exit = GNUNET_new (struct CadetExit);
1161     exit->peer = ad->peer;
1162     /* channel is closed, so insert at the end */
1163     GNUNET_CONTAINER_DLL_insert_tail (exit_head,
1164                                       exit_tail,
1165                                       exit);
1166   }
1167   exit->expiration = GNUNET_TIME_absolute_max (exit->expiration,
1168                                                GNUNET_TIME_absolute_ntoh (ad->expiration_time));
1169   if (dns_exit_available < MAX_OPEN_TUNNELS)
1170     try_open_exit ();
1171 }
1172
1173
1174 /**
1175  * @brief Main function that will be run by the scheduler.
1176  *
1177  * @param cls closure
1178  * @param args remaining command-line arguments
1179  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1180  * @param cfg_ configuration
1181  */
1182 static void
1183 run (void *cls, char *const *args GNUNET_UNUSED,
1184      const char *cfgfile GNUNET_UNUSED,
1185      const struct GNUNET_CONFIGURATION_Handle *cfg_)
1186 {
1187   struct GNUNET_HashCode dns_key;
1188
1189   cfg = cfg_;
1190   stats = GNUNET_STATISTICS_create ("pt",
1191                                     cfg);
1192   ipv4_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1193                                                   "pt",
1194                                                   "TUNNEL_IPV4");
1195   ipv6_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1196                                                   "pt",
1197                                                   "TUNNEL_IPV6");
1198   dns_channel = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1199                                                       "pt",
1200                                                       "TUNNEL_DNS");
1201   if (! (ipv4_pt || ipv6_pt || dns_channel))
1202   {
1203     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1204                 _("No useful service enabled.  Exiting.\n"));
1205     GNUNET_SCHEDULER_shutdown ();
1206     return;
1207   }
1208   GNUNET_SCHEDULER_add_shutdown (&cleanup, cls);
1209   if (ipv4_pt || ipv6_pt)
1210   {
1211     dns_post_handle
1212       = GNUNET_DNS_connect (cfg,
1213                             GNUNET_DNS_FLAG_POST_RESOLUTION,
1214                             &dns_post_request_handler,
1215                             NULL);
1216     if (NULL == dns_post_handle)
1217     {
1218       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1219                   _("Failed to connect to %s service.  Exiting.\n"),
1220                   "DNS");
1221       GNUNET_SCHEDULER_shutdown ();
1222       return;
1223     }
1224     vpn_handle = GNUNET_VPN_connect (cfg);
1225     if (NULL == vpn_handle)
1226     {
1227       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1228                   _("Failed to connect to %s service.  Exiting.\n"),
1229                   "VPN");
1230       GNUNET_SCHEDULER_shutdown ();
1231       return;
1232     }
1233   }
1234   if (dns_channel)
1235   {
1236     dns_pre_handle
1237       = GNUNET_DNS_connect (cfg,
1238                             GNUNET_DNS_FLAG_PRE_RESOLUTION,
1239                             &dns_pre_request_handler,
1240                             NULL);
1241     if (NULL == dns_pre_handle)
1242     {
1243       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1244                   _("Failed to connect to %s service.  Exiting.\n"),
1245                   "DNS");
1246       GNUNET_SCHEDULER_shutdown ();
1247       return;
1248     }
1249     cadet_handle = GNUNET_CADET_connecT (cfg);
1250     if (NULL == cadet_handle)
1251     {
1252       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1253                   _("Failed to connect to %s service.  Exiting.\n"),
1254                   "CADET");
1255       GNUNET_SCHEDULER_shutdown ();
1256       return;
1257     }
1258     dht = GNUNET_DHT_connect (cfg, 1);
1259     if (NULL == dht)
1260     {
1261       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1262                   _("Failed to connect to %s service.  Exiting.\n"),
1263                   "DHT");
1264       GNUNET_SCHEDULER_shutdown ();
1265       return;
1266     }
1267     GNUNET_CRYPTO_hash ("dns",
1268                         strlen ("dns"),
1269                         &dns_key);
1270     dht_get = GNUNET_DHT_get_start (dht,
1271                                     GNUNET_BLOCK_TYPE_DNS,
1272                                     &dns_key,
1273                                     1,
1274                                     GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1275                                     NULL, 0,
1276                                     &handle_dht_result,
1277                                     NULL);
1278   }
1279 }
1280
1281
1282 /**
1283  * The main function
1284  *
1285  * @param argc number of arguments from the command line
1286  * @param argv command line arguments
1287  * @return 0 ok, 1 on error
1288  */
1289 int
1290 main (int argc,
1291       char *const *argv)
1292 {
1293   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1294     GNUNET_GETOPT_OPTION_END
1295   };
1296   int ret;
1297
1298   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc,
1299                                                  argv,
1300                                                  &argc,
1301                                                  &argv))
1302     return 2;
1303   ret = (GNUNET_OK ==
1304          GNUNET_PROGRAM_run (argc,
1305                              argv,
1306                              "gnunet-daemon-pt",
1307                              gettext_noop ("Daemon to run to perform IP protocol translation to GNUnet"),
1308                              options,
1309                              &run,
1310                              NULL))
1311     ? 0
1312     : 1;
1313   GNUNET_free ((void*) argv);
1314   return ret;
1315 }
1316
1317
1318 /* end of gnunet-daemon-pt.c */