-convert vpn/exit/pt to use new CADET ports
[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   struct GNUNET_HashCode port;
337
338   GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER,
339                       strlen (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER),
340                       &port);
341   candidate_count = 0;
342   for (pos = exit_head; NULL != pos; pos = pos->next)
343     if (NULL == pos->cadet_channel)
344       candidate_count++;
345   candidate_selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
346                                                  candidate_count);
347   candidate_count = 0;
348   for (pos = exit_head; NULL != pos; pos = pos->next)
349     if (NULL == pos->cadet_channel)
350     {
351       candidate_count++;
352       if (candidate_selected < candidate_count)
353       {
354         /* move to the head of the DLL */
355         pos->cadet_channel
356           = GNUNET_CADET_channel_create (cadet_handle,
357                                          pos,
358                                          &pos->peer,
359                                          &port,
360                                          GNUNET_CADET_OPTION_DEFAULT);
361         if (NULL == pos->cadet_channel)
362         {
363           GNUNET_break (0);
364           continue;
365         }
366         GNUNET_CONTAINER_DLL_remove (exit_head,
367                                      exit_tail,
368                                      pos);
369         GNUNET_CONTAINER_DLL_insert (exit_head,
370                                      exit_tail,
371                                      pos);
372         dns_exit_available++;
373         return;
374       }
375     }
376   GNUNET_assert (NULL == exit_head);
377 }
378
379
380 /**
381  * Compute the weight of the given exit.  The higher the weight,
382  * the more likely it will be that the channel will be chosen.
383  * A weigt of zero means that we should close the channel as it
384  * is so bad, that we should not use it.
385  *
386  * @param exit exit to calculate the weight for
387  * @return weight of the channel
388  */
389 static uint32_t
390 get_channel_weight (struct CadetExit *exit)
391 {
392   uint32_t dropped;
393   uint32_t drop_percent;
394   uint32_t good_percent;
395
396   GNUNET_assert (exit->num_transmitted >= exit->num_answered);
397   dropped = exit->num_transmitted - exit->num_answered;
398   if (exit->num_transmitted > 0)
399     drop_percent = (uint32_t) ((100LL * dropped) / exit->num_transmitted);
400   else
401     drop_percent = 50; /* no data */
402   if ( (exit->num_transmitted > 20) &&
403        (drop_percent > 25) )
404     return 0; /* statistically significant, and > 25% loss, die */
405   good_percent = 100 - drop_percent;
406   GNUNET_assert (0 != good_percent);
407   if ( UINT32_MAX / good_percent / good_percent < exit->num_transmitted)
408     return UINT32_MAX; /* formula below would overflow */
409   return 1 + good_percent * good_percent * exit->num_transmitted;
410 }
411
412
413 /**
414  * Choose a cadet exit for a DNS request.  We try to use a channel
415  * that is reliable and currently available.  All existing
416  * channels are given a base weight of 1, plus a score relating
417  * to the total number of queries answered in relation to the
418  * total number of queries we sent to that channel.  That
419  * score is doubled if the channel is currently idle.
420  *
421  * @return NULL if no exit is known, otherwise the
422  *         exit that we should use to queue a message with
423  */
424 static struct CadetExit *
425 choose_exit ()
426 {
427   struct CadetExit *pos;
428   uint64_t total_transmitted;
429   uint64_t selected_offset;
430   uint32_t channel_weight;
431
432   total_transmitted = 0;
433   for (pos = exit_head; NULL != pos; pos = pos->next)
434   {
435     if (NULL == pos->cadet_channel)
436       break;
437     channel_weight = get_channel_weight (pos);
438     total_transmitted += channel_weight;
439     /* double weight for idle channels */
440     if (NULL == pos->cadet_th)
441       total_transmitted += channel_weight;
442   }
443   if (0 == total_transmitted)
444   {
445     /* no channels available, or only a very bad one... */
446     return exit_head;
447   }
448   selected_offset = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
449                                               total_transmitted);
450   total_transmitted = 0;
451   for (pos = exit_head; NULL != pos; pos = pos->next)
452   {
453     if (NULL == pos->cadet_channel)
454       break;
455     channel_weight = get_channel_weight (pos);
456     total_transmitted += channel_weight;
457     /* double weight for idle channels */
458     if (NULL == pos->cadet_th)
459       total_transmitted += channel_weight;
460     if (total_transmitted > selected_offset)
461       return pos;
462   }
463   GNUNET_break (0);
464   return NULL;
465 }
466
467
468 /**
469  * We're done modifying all records in the response.  Submit the reply
470  * and free the resources of the rc.
471  *
472  * @param rc context to process
473  */
474 static void
475 finish_request (struct ReplyContext *rc)
476 {
477   char *buf;
478   size_t buf_len;
479
480   if (GNUNET_SYSERR ==
481       GNUNET_DNSPARSER_pack (rc->dns,
482                              MAX_DNS_SIZE,
483                              &buf,
484                              &buf_len))
485   {
486     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
487                 _("Failed to pack DNS request.  Dropping.\n"));
488     GNUNET_DNS_request_drop (rc->rh);
489   }
490   else
491   {
492     GNUNET_STATISTICS_update (stats,
493                               gettext_noop ("# DNS requests mapped to VPN"),
494                               1, GNUNET_NO);
495     GNUNET_DNS_request_answer (rc->rh,
496                                buf_len,
497                                buf);
498     GNUNET_free (buf);
499   }
500   GNUNET_DNSPARSER_free_packet (rc->dns);
501   GNUNET_free (rc);
502 }
503
504
505 /**
506  * Process the next record of the given request context.
507  * When done, submit the reply and free the resources of
508  * the rc.
509  *
510  * @param rc context to process
511  */
512 static void
513 submit_request (struct ReplyContext *rc);
514
515
516 /**
517  * Callback invoked from the VPN service once a redirection is
518  * available.  Provides the IP address that can now be used to
519  * reach the requested destination.  We substitute the active
520  * record and then continue with 'submit_request' to look at
521  * the other records.
522  *
523  * @param cls our `struct ReplyContext`
524  * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
525  *                will match 'result_af' from the request
526  * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
527  *                that the VPN allocated for the redirection;
528  *                traffic to this IP will now be redirected to the
529  *                specified target peer; NULL on error
530  */
531 static void
532 vpn_allocation_callback (void *cls,
533                          int af,
534                          const void *address)
535 {
536   struct ReplyContext *rc = cls;
537
538   rc->rr = NULL;
539   if (af == AF_UNSPEC)
540   {
541     GNUNET_DNS_request_drop (rc->rh);
542     GNUNET_DNSPARSER_free_packet (rc->dns);
543     GNUNET_free (rc);
544     return;
545   }
546   GNUNET_STATISTICS_update (stats,
547                             gettext_noop ("# DNS records modified"),
548                             1,
549                             GNUNET_NO);
550   switch (rc->rec->type)
551   {
552   case GNUNET_DNSPARSER_TYPE_A:
553     GNUNET_assert (AF_INET == af);
554     GNUNET_memcpy (rc->rec->data.raw.data,
555                    address,
556                    sizeof (struct in_addr));
557     break;
558   case GNUNET_DNSPARSER_TYPE_AAAA:
559     GNUNET_assert (AF_INET6 == af);
560     GNUNET_memcpy (rc->rec->data.raw.data,
561                    address,
562                    sizeof (struct in6_addr));
563     break;
564   default:
565     GNUNET_assert (0);
566     return;
567   }
568   rc->rec = NULL;
569   submit_request (rc);
570 }
571
572
573 /**
574  * Modify the given DNS record by asking VPN to create a channel
575  * to the given address.  When done, continue with submitting
576  * other records from the request context ('submit_request' is
577  * our continuation).
578  *
579  * @param rc context to process
580  * @param rec record to modify
581  */
582 static void
583 modify_address (struct ReplyContext *rc,
584                 struct GNUNET_DNSPARSER_Record *rec)
585 {
586   int af;
587
588   switch (rec->type)
589   {
590   case GNUNET_DNSPARSER_TYPE_A:
591     af = AF_INET;
592     GNUNET_assert (rec->data.raw.data_len == sizeof (struct in_addr));
593     break;
594   case GNUNET_DNSPARSER_TYPE_AAAA:
595     af = AF_INET6;
596     GNUNET_assert (rec->data.raw.data_len == sizeof (struct in6_addr));
597     break;
598   default:
599     GNUNET_assert (0);
600     return;
601   }
602   rc->rec = rec;
603   rc->rr = GNUNET_VPN_redirect_to_ip (vpn_handle,
604                                       af,
605                                       af,
606                                       rec->data.raw.data,
607                                       GNUNET_TIME_relative_to_absolute (TIMEOUT),
608                                       &vpn_allocation_callback,
609                                       rc);
610 }
611
612
613 /**
614  * Process the next record of the given request context.
615  * When done, submit the reply and free the resources of
616  * the rc.
617  *
618  * @param rc context to process
619  */
620 static void
621 submit_request (struct ReplyContext *rc)
622 {
623   struct GNUNET_DNSPARSER_Record *ra;
624   unsigned int ra_len;
625   unsigned int i;
626
627   while (1)
628   {
629     switch (rc->group)
630     {
631     case ANSWERS:
632       ra = rc->dns->answers;
633       ra_len = rc->dns->num_answers;
634       break;
635     case AUTHORITY_RECORDS:
636       ra = rc->dns->authority_records;
637       ra_len = rc->dns->num_authority_records;
638       break;
639     case ADDITIONAL_RECORDS:
640       ra = rc->dns->additional_records;
641       ra_len = rc->dns->num_additional_records;
642       break;
643     case END:
644       finish_request (rc);
645       return;
646     default:
647       GNUNET_assert (0);
648     }
649     for (i=rc->offset;i<ra_len;i++)
650     {
651       switch (ra[i].type)
652       {
653       case GNUNET_DNSPARSER_TYPE_A:
654         if (ipv4_pt)
655         {
656           rc->offset = i + 1;
657           modify_address (rc,
658                           &ra[i]);
659           return;
660         }
661         break;
662       case GNUNET_DNSPARSER_TYPE_AAAA:
663         if (ipv6_pt)
664         {
665           rc->offset = i + 1;
666           modify_address (rc,
667                           &ra[i]);
668           return;
669         }
670         break;
671       }
672     }
673     rc->group++;
674   }
675 }
676
677
678 /**
679  * Test if any of the given records need protocol-translation work.
680  *
681  * @param ra array of records
682  * @param ra_len number of entries in @a ra
683  * @return #GNUNET_YES if any of the given records require protocol-translation
684  */
685 static int
686 work_test (const struct GNUNET_DNSPARSER_Record *ra,
687            unsigned int ra_len)
688 {
689   unsigned int i;
690
691   for (i=0;i<ra_len;i++)
692   {
693     switch (ra[i].type)
694     {
695     case GNUNET_DNSPARSER_TYPE_A:
696       if (ipv4_pt)
697         return GNUNET_YES;
698       break;
699     case GNUNET_DNSPARSER_TYPE_AAAA:
700       if (ipv6_pt)
701         return GNUNET_YES;
702       break;
703     }
704   }
705   return GNUNET_NO;
706 }
707
708
709 /**
710  * This function is called AFTER we got an IP address for a
711  * DNS request.  Now, the PT daemon has the chance to substitute
712  * the IP address with one from the VPN range to channel requests
713  * destined for this IP address via VPN and CADET.
714  *
715  * @param cls closure
716  * @param rh request handle to user for reply
717  * @param request_length number of bytes in request
718  * @param request udp payload of the DNS request
719  */
720 static void
721 dns_post_request_handler (void *cls,
722                           struct GNUNET_DNS_RequestHandle *rh,
723                           size_t request_length,
724                           const char *request)
725 {
726   struct GNUNET_DNSPARSER_Packet *dns;
727   struct ReplyContext *rc;
728   int work;
729
730   GNUNET_STATISTICS_update (stats,
731                             gettext_noop ("# DNS replies intercepted"),
732                             1, GNUNET_NO);
733   dns = GNUNET_DNSPARSER_parse (request,
734                                 request_length);
735   if (NULL == dns)
736   {
737     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
738                 _("Failed to parse DNS request.  Dropping.\n"));
739     GNUNET_DNS_request_drop (rh);
740     return;
741   }
742   work = GNUNET_NO;
743   work |= work_test (dns->answers,
744                      dns->num_answers);
745   work |= work_test (dns->authority_records,
746                      dns->num_authority_records);
747   work |= work_test (dns->additional_records,
748                      dns->num_additional_records);
749   if (! work)
750   {
751     GNUNET_DNS_request_forward (rh);
752     GNUNET_DNSPARSER_free_packet (dns);
753     return;
754   }
755   rc = GNUNET_new (struct ReplyContext);
756   rc->rh = rh;
757   rc->dns = dns;
758   rc->offset = 0;
759   rc->group = ANSWERS;
760   submit_request (rc);
761 }
762
763
764 /**
765  * Transmit a DNS request via CADET and move the request
766  * handle to the receive queue.
767  *
768  * @param cls the `struct CadetExit`
769  * @param size number of bytes available in buf
770  * @param buf where to copy the message
771  * @return number of bytes written to buf
772  */
773 static size_t
774 transmit_dns_request_to_cadet (void *cls,
775                               size_t size,
776                               void *buf)
777 {
778   struct CadetExit *exit = cls;
779   struct RequestContext *rc;
780   size_t mlen;
781
782   exit->cadet_th = NULL;
783   if (NULL == (rc = exit->transmit_queue_head))
784     return 0;
785   mlen = rc->mlen;
786   if (mlen > size)
787   {
788     exit->cadet_th
789       = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
790                                             GNUNET_NO,
791                                             TIMEOUT,
792                                             mlen,
793                                             &transmit_dns_request_to_cadet,
794                                             exit);
795     return 0;
796   }
797   GNUNET_assert (GNUNET_NO == rc->was_transmitted);
798   GNUNET_memcpy (buf,
799                  rc->cadet_message,
800                  mlen);
801   GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
802                                exit->transmit_queue_tail,
803                                rc);
804   rc->was_transmitted = GNUNET_YES;
805   GNUNET_CONTAINER_DLL_insert (exit->receive_queue_head,
806                                exit->receive_queue_tail,
807                                rc);
808   rc = exit->transmit_queue_head;
809   if (NULL != rc)
810     exit->cadet_th = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
811                                                        GNUNET_NO,
812                                                        TIMEOUT,
813                                                        rc->mlen,
814                                                        &transmit_dns_request_to_cadet,
815                                                        exit);
816   return mlen;
817 }
818
819
820 /**
821  * Task run if the time to answer a DNS request via CADET is over.
822  *
823  * @param cls the `struct RequestContext` to abort
824  */
825 static void
826 timeout_request (void *cls)
827 {
828   struct RequestContext *rc = cls;
829   struct CadetExit *exit = rc->exit;
830
831   if (rc->was_transmitted)
832   {
833     exit->num_transmitted++;
834     GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
835                                  exit->receive_queue_tail,
836                                  rc);
837   }
838   else
839   {
840     GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
841                                  exit->transmit_queue_tail,
842                                  rc);
843   }
844   GNUNET_STATISTICS_update (stats,
845                             gettext_noop ("# DNS requests dropped (timeout)"),
846                             1,
847                             GNUNET_NO);
848   GNUNET_DNS_request_drop (rc->rh);
849   GNUNET_free (rc);
850   if ( (0 == get_channel_weight (exit)) &&
851        (NULL == exit->receive_queue_head) &&
852        (NULL == exit->transmit_queue_head) )
853   {
854     /* this straw broke the camel's back: this channel now has
855        such a low score that it will not be used; close it! */
856     GNUNET_assert (NULL == exit->cadet_th);
857     GNUNET_CADET_channel_destroy (exit->cadet_channel);
858     exit->cadet_channel = NULL;
859     GNUNET_CONTAINER_DLL_remove (exit_head,
860                                  exit_tail,
861                                  exit);
862     GNUNET_CONTAINER_DLL_insert_tail (exit_head,
863                                       exit_tail,
864                                       exit);
865     /* go back to semi-innocent: mark as not great, but
866        avoid a prohibitively negative score (see
867        #get_channel_weight, which checks for a certain
868        minimum number of transmissions before making
869        up an opinion) */
870     exit->num_transmitted = 5;
871     exit->num_answered = 0;
872     dns_exit_available--;
873     /* now try to open an alternative exit */
874     try_open_exit ();
875   }
876 }
877
878
879 /**
880  * This function is called *before* the DNS request has been
881  * given to a "local" DNS resolver.  Channeling for DNS requests
882  * was enabled, so we now need to send the request via some CADET
883  * channel to a DNS EXIT for resolution.
884  *
885  * @param cls closure
886  * @param rh request handle to user for reply
887  * @param request_length number of bytes in request
888  * @param request udp payload of the DNS request
889  */
890 static void
891 dns_pre_request_handler (void *cls,
892                          struct GNUNET_DNS_RequestHandle *rh,
893                          size_t request_length,
894                          const char *request)
895 {
896   struct RequestContext *rc;
897   size_t mlen;
898   struct GNUNET_MessageHeader hdr;
899   struct GNUNET_TUN_DnsHeader dns;
900   struct CadetExit *exit;
901
902   GNUNET_STATISTICS_update (stats,
903                             gettext_noop ("# DNS requests intercepted"),
904                             1, GNUNET_NO);
905   if (0 == dns_exit_available)
906   {
907     GNUNET_STATISTICS_update (stats,
908                               gettext_noop ("# DNS requests dropped (DNS cadet channel down)"),
909                               1, GNUNET_NO);
910     GNUNET_DNS_request_drop (rh);
911     return;
912   }
913   if (request_length < sizeof (dns))
914   {
915     GNUNET_STATISTICS_update (stats,
916                               gettext_noop ("# DNS requests dropped (malformed)"),
917                               1, GNUNET_NO);
918     GNUNET_DNS_request_drop (rh);
919     return;
920   }
921   GNUNET_memcpy (&dns, request, sizeof (dns));
922   mlen = sizeof (struct GNUNET_MessageHeader) + request_length;
923   exit = choose_exit ();
924   GNUNET_assert (NULL != exit);
925   GNUNET_assert (NULL != exit->cadet_channel);
926   rc = GNUNET_malloc (sizeof (struct RequestContext) + mlen);
927   rc->exit = exit;
928   rc->rh = rh;
929   rc->cadet_message = (const struct GNUNET_MessageHeader*) &rc[1];
930   rc->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
931                                                    &timeout_request,
932                                                    rc);
933   rc->dns_id = dns.id;
934   rc->mlen = mlen;
935   hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET);
936   hdr.size = htons (mlen);
937   GNUNET_memcpy (&rc[1], &hdr, sizeof (struct GNUNET_MessageHeader));
938   GNUNET_memcpy (&(((char*)&rc[1])[sizeof (struct GNUNET_MessageHeader)]),
939           request,
940           request_length);
941   GNUNET_CONTAINER_DLL_insert_tail (exit->transmit_queue_head,
942                                     exit->transmit_queue_tail,
943                                     rc);
944   if (NULL == exit->cadet_th)
945     exit->cadet_th = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
946                                                        GNUNET_NO,
947                                                        TIMEOUT,
948                                                        mlen,
949                                                        &transmit_dns_request_to_cadet,
950                                                        exit);
951 }
952
953
954 /**
955  * Process a request via cadet to perform a DNS query.
956  *
957  * @param cls NULL
958  * @param channel connection to the other end
959  * @param channel_ctx pointer to our `struct CadetExit`
960  * @param message the actual message
961  * @return #GNUNET_OK to keep the connection open,
962  *         #GNUNET_SYSERR to close it (signal serious error)
963  */
964 static int
965 receive_dns_response (void *cls,
966                       struct GNUNET_CADET_Channel *channel,
967                       void **channel_ctx,
968                       const struct GNUNET_MessageHeader *message)
969 {
970   struct CadetExit *exit = *channel_ctx;
971   struct GNUNET_TUN_DnsHeader dns;
972   size_t mlen;
973   struct RequestContext *rc;
974
975   mlen = ntohs (message->size);
976   mlen -= sizeof (struct GNUNET_MessageHeader);
977   if (mlen < sizeof (struct GNUNET_TUN_DnsHeader))
978   {
979     GNUNET_break_op (0);
980     return GNUNET_SYSERR;
981   }
982   GNUNET_memcpy (&dns, &message[1], sizeof (dns));
983   for (rc = exit->receive_queue_head; NULL != rc; rc = rc->next)
984   {
985     GNUNET_assert (GNUNET_YES == rc->was_transmitted);
986     if (dns.id == rc->dns_id)
987     {
988       GNUNET_STATISTICS_update (stats,
989                                 gettext_noop ("# DNS replies received"),
990                                 1, GNUNET_NO);
991       GNUNET_DNS_request_answer (rc->rh,
992                                  mlen,
993                                  (const void*) &message[1]);
994       GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
995                                    exit->receive_queue_tail,
996                                    rc);
997       GNUNET_SCHEDULER_cancel (rc->timeout_task);
998       GNUNET_free (rc);
999       exit->num_answered++;
1000       exit->num_transmitted++;
1001       return GNUNET_OK;
1002     }
1003   }
1004   GNUNET_STATISTICS_update (stats,
1005                             gettext_noop ("# DNS replies dropped (too late?)"),
1006                             1, GNUNET_NO);
1007   return GNUNET_OK;
1008 }
1009
1010
1011 /**
1012  * Abort all pending DNS requests with the given cadet exit.
1013  *
1014  * @param exit cadet exit to abort requests for
1015  */
1016 static void
1017 abort_all_requests (struct CadetExit *exit)
1018 {
1019   struct RequestContext *rc;
1020
1021   while (NULL != (rc = exit->receive_queue_head))
1022   {
1023     GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1024                                  exit->receive_queue_tail,
1025                                  rc);
1026     GNUNET_DNS_request_drop (rc->rh);
1027     GNUNET_SCHEDULER_cancel (rc->timeout_task);
1028     GNUNET_free (rc);
1029   }
1030   while (NULL != (rc = exit->transmit_queue_head))
1031   {
1032     GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
1033                                  exit->transmit_queue_tail,
1034                                  rc);
1035     GNUNET_DNS_request_drop (rc->rh);
1036     GNUNET_SCHEDULER_cancel (rc->timeout_task);
1037     GNUNET_free (rc);
1038   }
1039 }
1040
1041
1042 /**
1043  * Function scheduled as very last function, cleans up after us
1044  *
1045  * @param cls closure, NULL
1046  */
1047 static void
1048 cleanup (void *cls)
1049 {
1050   struct CadetExit *exit;
1051
1052   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1053               "Protocol translation daemon is shutting down now\n");
1054   if (NULL != vpn_handle)
1055   {
1056     GNUNET_VPN_disconnect (vpn_handle);
1057     vpn_handle = NULL;
1058   }
1059   while (NULL != (exit = exit_head))
1060   {
1061     GNUNET_CONTAINER_DLL_remove (exit_head,
1062                                  exit_tail,
1063                                  exit);
1064     if (NULL != exit->cadet_th)
1065     {
1066       GNUNET_CADET_notify_transmit_ready_cancel (exit->cadet_th);
1067       exit->cadet_th = NULL;
1068     }
1069     if (NULL != exit->cadet_channel)
1070     {
1071       GNUNET_CADET_channel_destroy (exit->cadet_channel);
1072       exit->cadet_channel = NULL;
1073     }
1074     abort_all_requests (exit);
1075     GNUNET_free (exit);
1076   }
1077   if (NULL != cadet_handle)
1078   {
1079     GNUNET_CADET_disconnect (cadet_handle);
1080     cadet_handle = NULL;
1081   }
1082   if (NULL != dns_post_handle)
1083   {
1084     GNUNET_DNS_disconnect (dns_post_handle);
1085     dns_post_handle = NULL;
1086   }
1087   if (NULL != dns_pre_handle)
1088   {
1089     GNUNET_DNS_disconnect (dns_pre_handle);
1090     dns_pre_handle = NULL;
1091   }
1092   if (NULL != stats)
1093   {
1094     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
1095     stats = NULL;
1096   }
1097   if (NULL != dht_get)
1098   {
1099     GNUNET_DHT_get_stop (dht_get);
1100     dht_get = NULL;
1101   }
1102   if (NULL != dht)
1103   {
1104     GNUNET_DHT_disconnect (dht);
1105     dht = NULL;
1106   }
1107 }
1108
1109
1110 /**
1111  * Function called whenever a channel is destroyed.  Should clean up
1112  * the associated state and attempt to build a new one.
1113  *
1114  * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
1115  *
1116  * @param cls closure (the `struct CadetExit` set from #GNUNET_CADET_connect)
1117  * @param channel connection to the other end (henceforth invalid)
1118  * @param channel_ctx place where local state associated
1119  *                   with the channel is stored
1120  */
1121 static void
1122 cadet_channel_end_cb (void *cls,
1123                     const struct GNUNET_CADET_Channel *channel,
1124                     void *channel_ctx)
1125 {
1126   struct CadetExit *exit = channel_ctx;
1127   struct CadetExit *alt;
1128   struct RequestContext *rc;
1129
1130   if (NULL != exit->cadet_th)
1131   {
1132     GNUNET_CADET_notify_transmit_ready_cancel (exit->cadet_th);
1133     exit->cadet_th = NULL;
1134   }
1135   exit->cadet_channel = NULL;
1136   dns_exit_available--;
1137   /* open alternative channels */
1138   try_open_exit ();
1139   if (NULL == exit->cadet_channel)
1140   {
1141     /* our channel is now closed, move our requests to an alternative
1142        channel */
1143     alt = choose_exit ();
1144     while (NULL != (rc = exit->transmit_queue_head))
1145     {
1146       GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
1147                                    exit->transmit_queue_tail,
1148                                    rc);
1149       rc->exit = alt;
1150       GNUNET_CONTAINER_DLL_insert (alt->transmit_queue_head,
1151                                    alt->transmit_queue_tail,
1152                                    rc);
1153     }
1154     while (NULL != (rc = exit->receive_queue_head))
1155     {
1156       GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1157                                    exit->receive_queue_tail,
1158                                    rc);
1159       rc->was_transmitted = GNUNET_NO;
1160       rc->exit = alt;
1161       GNUNET_CONTAINER_DLL_insert (alt->transmit_queue_head,
1162                                    alt->transmit_queue_tail,
1163                                    rc);
1164     }
1165   }
1166   else
1167   {
1168     /* the same peer was chosen, just make sure the queue processing is restarted */
1169     alt = exit;
1170   }
1171   if ( (NULL == alt->cadet_th) &&
1172        (NULL != (rc = alt->transmit_queue_head)) )
1173     alt->cadet_th
1174       = GNUNET_CADET_notify_transmit_ready (alt->cadet_channel,
1175                                             GNUNET_NO,
1176                                             TIMEOUT,
1177                                             rc->mlen,
1178                                             &transmit_dns_request_to_cadet,
1179                                             alt);
1180 }
1181
1182
1183 /**
1184  * Function called whenever we find an advertisement for a
1185  * DNS exit in the DHT.  If we don't have a cadet channel,
1186  * we should build one; otherwise, we should save the
1187  * advertisement for later use.
1188  *
1189  * @param cls closure
1190  * @param exp when will this value expire
1191  * @param key key of the result
1192  * @param get_path peers on reply path (or NULL if not recorded)
1193  *                 [0] = datastore's first neighbor, [length - 1] = local peer
1194  * @param get_path_length number of entries in @a get_path
1195  * @param put_path peers on the PUT path (or NULL if not recorded)
1196  *                 [0] = origin, [length - 1] = datastore
1197  * @param put_path_length number of entries in @a put_path
1198  * @param type type of the result
1199  * @param size number of bytes in @a data
1200  * @param data pointer to the result data
1201  */
1202 static void
1203 handle_dht_result (void *cls,
1204                    struct GNUNET_TIME_Absolute exp,
1205                    const struct GNUNET_HashCode *key,
1206                    const struct GNUNET_PeerIdentity *get_path,
1207                    unsigned int get_path_length,
1208                    const struct GNUNET_PeerIdentity *put_path,
1209                    unsigned int put_path_length,
1210                    enum GNUNET_BLOCK_Type type,
1211                    size_t size, const void *data)
1212 {
1213   const struct GNUNET_DNS_Advertisement *ad;
1214   struct CadetExit *exit;
1215
1216   if (sizeof (struct GNUNET_DNS_Advertisement) != size)
1217   {
1218     GNUNET_break (0);
1219     return;
1220   }
1221   ad = data;
1222   for (exit = exit_head; NULL != exit; exit = exit->next)
1223     if (0 == memcmp (&ad->peer,
1224                      &exit->peer,
1225                      sizeof (struct GNUNET_PeerIdentity)))
1226       break;
1227   if (NULL == exit)
1228   {
1229     exit = GNUNET_new (struct CadetExit);
1230     exit->peer = ad->peer;
1231     /* channel is closed, so insert at the end */
1232     GNUNET_CONTAINER_DLL_insert_tail (exit_head,
1233                                       exit_tail,
1234                                       exit);
1235   }
1236   exit->expiration = GNUNET_TIME_absolute_max (exit->expiration,
1237                                                GNUNET_TIME_absolute_ntoh (ad->expiration_time));
1238   if (dns_exit_available < MAX_OPEN_TUNNELS)
1239     try_open_exit ();
1240 }
1241
1242
1243 /**
1244  * @brief Main function that will be run by the scheduler.
1245  *
1246  * @param cls closure
1247  * @param args remaining command-line arguments
1248  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1249  * @param cfg_ configuration
1250  */
1251 static void
1252 run (void *cls, char *const *args GNUNET_UNUSED,
1253      const char *cfgfile GNUNET_UNUSED,
1254      const struct GNUNET_CONFIGURATION_Handle *cfg_)
1255 {
1256   struct GNUNET_HashCode dns_key;
1257
1258   cfg = cfg_;
1259   stats = GNUNET_STATISTICS_create ("pt",
1260                                     cfg);
1261   ipv4_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1262                                                   "pt",
1263                                                   "TUNNEL_IPV4");
1264   ipv6_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1265                                                   "pt",
1266                                                   "TUNNEL_IPV6");
1267   dns_channel = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1268                                                       "pt",
1269                                                       "TUNNEL_DNS");
1270   if (! (ipv4_pt || ipv6_pt || dns_channel))
1271   {
1272     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1273                 _("No useful service enabled.  Exiting.\n"));
1274     GNUNET_SCHEDULER_shutdown ();
1275     return;
1276   }
1277   GNUNET_SCHEDULER_add_shutdown (&cleanup, cls);
1278   if (ipv4_pt || ipv6_pt)
1279   {
1280     dns_post_handle
1281       = GNUNET_DNS_connect (cfg,
1282                             GNUNET_DNS_FLAG_POST_RESOLUTION,
1283                             &dns_post_request_handler,
1284                             NULL);
1285     if (NULL == dns_post_handle)
1286     {
1287       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1288                   _("Failed to connect to %s service.  Exiting.\n"),
1289                   "DNS");
1290       GNUNET_SCHEDULER_shutdown ();
1291       return;
1292     }
1293     vpn_handle = GNUNET_VPN_connect (cfg);
1294     if (NULL == vpn_handle)
1295     {
1296       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1297                   _("Failed to connect to %s service.  Exiting.\n"),
1298                   "VPN");
1299       GNUNET_SCHEDULER_shutdown ();
1300       return;
1301     }
1302   }
1303   if (dns_channel)
1304   {
1305     static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1306       {&receive_dns_response, GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET, 0},
1307       {NULL, 0, 0}
1308     };
1309
1310     dns_pre_handle
1311       = GNUNET_DNS_connect (cfg,
1312                             GNUNET_DNS_FLAG_PRE_RESOLUTION,
1313                             &dns_pre_request_handler,
1314                             NULL);
1315     if (NULL == dns_pre_handle)
1316     {
1317       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1318                   _("Failed to connect to %s service.  Exiting.\n"),
1319                   "DNS");
1320       GNUNET_SCHEDULER_shutdown ();
1321       return;
1322     }
1323     cadet_handle = GNUNET_CADET_connect (cfg,
1324                                          NULL,
1325                                          &cadet_channel_end_cb,
1326                                          cadet_handlers);
1327     if (NULL == cadet_handle)
1328     {
1329       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1330                   _("Failed to connect to %s service.  Exiting.\n"),
1331                   "CADET");
1332       GNUNET_SCHEDULER_shutdown ();
1333       return;
1334     }
1335     dht = GNUNET_DHT_connect (cfg, 1);
1336     if (NULL == dht)
1337     {
1338       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1339                   _("Failed to connect to %s service.  Exiting.\n"),
1340                   "DHT");
1341       GNUNET_SCHEDULER_shutdown ();
1342       return;
1343     }
1344     GNUNET_CRYPTO_hash ("dns",
1345                         strlen ("dns"),
1346                         &dns_key);
1347     dht_get = GNUNET_DHT_get_start (dht,
1348                                     GNUNET_BLOCK_TYPE_DNS,
1349                                     &dns_key,
1350                                     1,
1351                                     GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1352                                     NULL, 0,
1353                                     &handle_dht_result,
1354                                     NULL);
1355   }
1356 }
1357
1358
1359 /**
1360  * The main function
1361  *
1362  * @param argc number of arguments from the command line
1363  * @param argv command line arguments
1364  * @return 0 ok, 1 on error
1365  */
1366 int
1367 main (int argc,
1368       char *const *argv)
1369 {
1370   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1371     GNUNET_GETOPT_OPTION_END
1372   };
1373   int ret;
1374
1375   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc,
1376                                                  argv,
1377                                                  &argc,
1378                                                  &argv))
1379     return 2;
1380   ret = (GNUNET_OK ==
1381          GNUNET_PROGRAM_run (argc,
1382                              argv,
1383                              "gnunet-daemon-pt",
1384                              gettext_noop ("Daemon to run to perform IP protocol translation to GNUnet"),
1385                              options,
1386                              &run,
1387                              NULL))
1388     ? 0
1389     : 1;
1390   GNUNET_free ((void*) argv);
1391   return ret;
1392 }
1393
1394
1395 /* end of gnunet-daemon-pt.c */