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