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