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