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