In Windows, pipes, files and the console have to be accessed
[oweals/gnunet.git] / src / vpn / gnunet-service-vpn.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010, 2011, 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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file vpn/gnunet-service-vpn.c
23  * @brief service that opens a virtual interface and allows its clients
24  *        to allocate IPs on the virtual interface and to then redirect
25  *        IP traffic received on those IPs via the GNUnet mesh 
26  * @author Philipp Toelke
27  * @author Christian Grothoff
28  */
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_common.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_applications.h"
34 #include "gnunet_mesh_service.h"
35 #include "gnunet_statistics_service.h"
36 #include "gnunet_constants.h"
37 #include "gnunet_tun_lib.h"
38 #include "gnunet_regex_lib.h"
39 #include "vpn.h"
40 #include "exit.h"
41
42
43 /**
44  * Maximum number of messages we allow in the queue for mesh.
45  */
46 #define MAX_MESSAGE_QUEUE_SIZE 4
47
48
49 /**
50  * State we keep for each of our tunnels.
51  */
52 struct TunnelState;
53
54
55 /**
56  * Information we track for each IP address to determine which tunnel
57  * to send the traffic over to the destination.
58  */
59 struct DestinationEntry
60 {
61
62   /**
63    * Key under which this entry is in the 'destination_map' (only valid
64    * if 'heap_node != NULL').
65    */
66   struct GNUNET_HashCode key;
67
68   /**
69    * Pre-allocated tunnel for this destination, or NULL for none.
70    */
71   struct TunnelState *ts;
72
73   /**
74    * Entry for this entry in the destination_heap.
75    */
76   struct GNUNET_CONTAINER_HeapNode *heap_node;
77
78   /**
79    * GNUNET_NO if this is a tunnel to an Internet-exit,
80    * GNUNET_YES if this tunnel is to a service.
81    */
82   int is_service;
83
84   /**
85    * Details about the connection (depending on is_service).
86    */
87   union
88   {
89
90     struct
91     {
92       /**
93        * The description of the service (only used for service tunnels).
94        */
95       struct GNUNET_HashCode service_descriptor;
96
97       /**
98        * Peer offering the service.
99        */
100       struct GNUNET_PeerIdentity target;
101
102     } service_destination;
103
104     struct 
105     {
106   
107       /**
108        * Address family used (AF_INET or AF_INET6).
109        */
110       int af;
111       
112       /**
113        * IP address of the ultimate destination (only used for exit tunnels).
114        */
115       union
116       {
117         /**
118          * Address if af is AF_INET.
119          */
120         struct in_addr v4;
121         
122         /**
123          * Address if af is AF_INET6.
124          */
125         struct in6_addr v6;
126       } ip;
127
128     } exit_destination;
129
130   } details;
131     
132 };
133
134
135 /**
136  * A messages we have in queue for a particular tunnel.
137  */
138 struct TunnelMessageQueueEntry
139 {
140   /**
141    * This is a doubly-linked list.
142    */
143   struct TunnelMessageQueueEntry *next;
144
145   /**
146    * This is a doubly-linked list.
147    */
148   struct TunnelMessageQueueEntry *prev;
149   
150   /**
151    * Number of bytes in 'msg'.
152    */
153   size_t len;
154
155   /**
156    * Message to transmit, allocated at the end of this struct.
157    */
158   const void *msg;
159 };
160
161
162 /**
163  * State we keep for each of our tunnels.
164  */
165 struct TunnelState
166 {
167
168   /**
169    * Information about the tunnel to use, NULL if no tunnel
170    * is available right now.
171    */
172   struct GNUNET_MESH_Tunnel *tunnel;
173
174   /**
175    * Active transmission handle, NULL for none.
176    */
177   struct GNUNET_MESH_TransmitHandle *th;
178
179   /**
180    * Entry for this entry in the tunnel_heap, NULL as long as this
181    * tunnel state is not fully bound.
182    */
183   struct GNUNET_CONTAINER_HeapNode *heap_node;
184
185   /**
186    * Head of list of messages scheduled for transmission.
187    */
188   struct TunnelMessageQueueEntry *tmq_head;
189
190   /**
191    * Tail of list of messages scheduled for transmission.
192    */
193   struct TunnelMessageQueueEntry *tmq_tail;  
194
195   /**
196    * Client that needs to be notified about the tunnel being
197    * up as soon as a peer is connected; NULL for none.
198    */
199   struct GNUNET_SERVER_Client *client;
200
201   /**
202    * Destination entry that has a pointer to this tunnel state;
203    * NULL if this tunnel state is in the tunnel map.
204    */
205   struct DestinationEntry *destination_container;
206
207   /**
208    * ID of the client request that caused us to setup this entry.
209    */ 
210   uint64_t request_id;
211
212   /**
213    * Destination to which this tunnel leads.  Note that
214    * this struct is NOT in the destination_map (but a
215    * local copy) and that the 'heap_node' should always
216    * be NULL.
217    */
218   struct DestinationEntry destination;
219
220   /**
221    * Task scheduled to destroy the tunnel (or NO_TASK).
222    */
223   GNUNET_SCHEDULER_TaskIdentifier destroy_task;
224
225   /**
226    * Addess family used for this tunnel on the local TUN interface.
227    */
228   int af;
229
230   /**
231    * Length of the doubly linked 'tmq_head/tmq_tail' list.
232    */
233   unsigned int tmq_length;
234
235   /**
236    * IPPROTO_TCP or IPPROTO_UDP once bound.
237    */
238   uint8_t protocol;
239
240   /**
241    * IP address of the source on our end, initially uninitialized.
242    */
243   union
244   {
245     /**
246      * Address if af is AF_INET.
247      */
248     struct in_addr v4;
249     
250     /**
251      * Address if af is AF_INET6.
252      */
253     struct in6_addr v6;
254
255   } source_ip;
256
257   /**
258    * Destination IP address used by the source on our end (this is the IP
259    * that we pick freely within the VPN's tunnel IP range).
260    */
261   union
262   {
263     /**
264      * Address if af is AF_INET.
265      */
266     struct in_addr v4;
267     
268     /**
269      * Address if af is AF_INET6.
270      */
271     struct in6_addr v6;
272
273   } destination_ip;
274
275   /**
276    * Source port used by the sender on our end; 0 for uninitialized.
277    */
278   uint16_t source_port;
279
280   /**
281    * Destination port used by the sender on our end; 0 for uninitialized.
282    */
283   uint16_t destination_port;
284
285 };
286
287
288 /**
289  * Return value from 'main'.
290  */
291 static int global_ret;
292
293 /**
294  * Configuration we use.
295  */
296 static const struct GNUNET_CONFIGURATION_Handle *cfg;
297
298 /**
299  * Handle to the mesh service.
300  */
301 static struct GNUNET_MESH_Handle *mesh_handle;
302
303 /**
304  * Map from IP address to destination information (possibly with a
305  * MESH tunnel handle for fast setup).
306  */
307 static struct GNUNET_CONTAINER_MultiHashMap *destination_map;
308
309 /**
310  * Min-Heap sorted by activity time to expire old mappings.
311  */
312 static struct GNUNET_CONTAINER_Heap *destination_heap;
313
314 /**
315  * Map from source and destination address (IP+port) to connection
316  * information (mostly with the respective MESH tunnel handle).
317  */
318 static struct GNUNET_CONTAINER_MultiHashMap *tunnel_map;
319
320 /**
321  * Min-Heap sorted by activity time to expire old mappings; values are
322  * of type 'struct TunnelState'.
323  */
324 static struct GNUNET_CONTAINER_Heap *tunnel_heap;
325
326 /**
327  * Statistics.
328  */
329 static struct GNUNET_STATISTICS_Handle *stats;
330
331 /**
332  * The handle to the VPN helper process "gnunet-helper-vpn".
333  */
334 static struct GNUNET_HELPER_Handle *helper_handle;
335
336 /**
337  * Arguments to the vpn helper.
338  */
339 static char *vpn_argv[7];
340
341 /**
342  * Length of the prefix of the VPN's IPv6 network.
343  */
344 static unsigned long long ipv6prefix;
345
346 /**
347  * Notification context for sending replies to clients.
348  */
349 static struct GNUNET_SERVER_NotificationContext *nc;
350
351 /**
352  * If there are more than this number of address-mappings, old ones
353  * will be removed
354  */
355 static unsigned long long max_destination_mappings;
356
357 /**
358  * If there are more than this number of open tunnels, old ones
359  * will be removed
360  */
361 static unsigned long long max_tunnel_mappings;
362
363
364 /**
365  * Compute the key under which we would store an entry in the
366  * destination_map for the given IP address.
367  *
368  * @param af address family (AF_INET or AF_INET6)
369  * @param address IP address, struct in_addr or struct in6_addr
370  * @param key where to store the key
371  */
372 static void
373 get_destination_key_from_ip (int af,
374                              const void *address,
375                              struct GNUNET_HashCode *key)
376 {
377   switch (af)
378   {
379   case AF_INET:
380     GNUNET_CRYPTO_hash (address,
381                         sizeof (struct in_addr),
382                         key);
383     break;
384   case AF_INET6:
385     GNUNET_CRYPTO_hash (address,
386                         sizeof (struct in6_addr),
387                         key);
388     break;
389   default:
390     GNUNET_assert (0);
391     break;
392   }
393 }
394
395
396 /**
397  * Compute the key under which we would store an entry in the
398  * tunnel_map for the given socket address pair.
399  *
400  * @param af address family (AF_INET or AF_INET6)
401  * @param protocol IPPROTO_TCP or IPPROTO_UDP
402  * @param source_ip sender's source IP, struct in_addr or struct in6_addr
403  * @param source_port sender's source port
404  * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr
405  * @param destination_port sender's destination port
406  * @param key where to store the key
407  */
408 static void
409 get_tunnel_key_from_ips (int af,
410                          uint8_t protocol,
411                          const void *source_ip,
412                          uint16_t source_port,
413                          const void *destination_ip,
414                          uint16_t destination_port,
415                          struct GNUNET_HashCode *key)
416 {
417   char *off;
418
419   memset (key, 0, sizeof (struct GNUNET_HashCode));
420   /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash,
421      so we put the ports in there (and hope for few collisions) */
422   off = (char*) key;
423   memcpy (off, &source_port, sizeof (uint16_t));
424   off += sizeof (uint16_t);
425   memcpy (off, &destination_port, sizeof (uint16_t));
426   off += sizeof (uint16_t);
427   switch (af)
428   {
429   case AF_INET:
430     memcpy (off, source_ip, sizeof (struct in_addr));
431     off += sizeof (struct in_addr);
432     memcpy (off, destination_ip, sizeof (struct in_addr));
433     off += sizeof (struct in_addr);
434     break;
435   case AF_INET6:
436     memcpy (off, source_ip, sizeof (struct in6_addr));
437     off += sizeof (struct in6_addr);
438     memcpy (off, destination_ip, sizeof (struct in6_addr));
439     off += sizeof (struct in6_addr);
440     break;
441   default:
442     GNUNET_assert (0);
443     break;
444   }
445   memcpy (off, &protocol, sizeof (uint8_t));
446   off += sizeof (uint8_t);  
447 }
448
449
450 /**
451  * Notify the client about the result of its request.
452  *
453  * @param client client to notify
454  * @param request_id original request ID to include in response
455  * @param result_af resulting address family
456  * @param addr resulting IP address
457  */
458 static void
459 send_client_reply (struct GNUNET_SERVER_Client *client,
460                    uint64_t request_id,
461                    int result_af,
462                    const void *addr)
463 {
464   char buf[sizeof (struct RedirectToIpResponseMessage) + sizeof (struct in6_addr)] GNUNET_ALIGN;
465   struct RedirectToIpResponseMessage *res;
466   size_t rlen;
467
468   switch (result_af)
469   {
470   case AF_INET:
471     rlen = sizeof (struct in_addr);    
472     break;
473   case AF_INET6:
474     rlen = sizeof (struct in6_addr);
475     break;
476   case AF_UNSPEC:
477     rlen = 0;
478     break;
479   default:
480     GNUNET_assert (0);
481     return;
482   }
483   res = (struct RedirectToIpResponseMessage *) buf;
484   res->header.size = htons (sizeof (struct RedirectToIpResponseMessage) + rlen);
485   res->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP);
486   res->result_af = htonl (result_af);
487   res->request_id = request_id;
488   memcpy (&res[1], addr, rlen);
489   GNUNET_SERVER_notification_context_add (nc, client);
490   GNUNET_SERVER_notification_context_unicast (nc,
491                                               client,
492                                               &res->header,
493                                               GNUNET_NO);
494 }
495
496
497 /**
498  * Free resources associated with a tunnel state.
499  *
500  * @param ts state to free
501  */
502 static void
503 free_tunnel_state (struct TunnelState *ts)
504 {
505   struct GNUNET_HashCode key;
506   struct TunnelMessageQueueEntry *tnq;
507   struct GNUNET_MESH_Tunnel *tunnel;
508
509   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
510               "Cleaning up tunnel state\n");
511   GNUNET_STATISTICS_update (stats,
512                             gettext_noop ("# Active tunnels"),
513                             -1, GNUNET_NO);
514   while (NULL != (tnq = ts->tmq_head))
515   {
516     GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
517                                  ts->tmq_tail,
518                                  tnq);
519     ts->tmq_length--;
520     GNUNET_free (tnq);
521   }
522   GNUNET_assert (0 == ts->tmq_length);
523   if (NULL != ts->client)
524   {
525     GNUNET_SERVER_client_drop (ts->client);
526     ts->client = NULL;
527   }
528   if (NULL != ts->th)
529   {
530     GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
531     ts->th = NULL;
532   }
533   GNUNET_assert (NULL == ts->destination.heap_node);
534   if (NULL != (tunnel = ts->tunnel))
535   {
536     ts->tunnel = NULL;
537     GNUNET_MESH_tunnel_destroy (tunnel);
538   }
539   if (GNUNET_SCHEDULER_NO_TASK != ts->destroy_task)
540   {
541     GNUNET_SCHEDULER_cancel (ts->destroy_task);
542     ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
543   }
544   if (NULL != ts->heap_node)
545   {
546     GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
547     ts->heap_node = NULL;
548     get_tunnel_key_from_ips (ts->af,
549                              ts->protocol,
550                              &ts->source_ip,
551                              ts->source_port,
552                              &ts->destination_ip,
553                              ts->destination_port,
554                              &key);
555     GNUNET_assert (GNUNET_YES ==
556                    GNUNET_CONTAINER_multihashmap_remove (tunnel_map,
557                                                          &key,
558                                                          ts));
559   }
560   if (NULL != ts->destination_container)
561   {
562     GNUNET_assert (ts == ts->destination_container->ts);
563     ts->destination_container->ts = NULL;
564     ts->destination_container = NULL;
565   }
566   GNUNET_free (ts);
567 }
568
569
570 /**
571  * Destroy the mesh tunnel.
572  *
573  * @param cls the 'struct TunnelState' with the tunnel to destroy
574  * @param tc scheduler context
575  */
576 static void
577 destroy_tunnel_task (void *cls,
578                      const struct GNUNET_SCHEDULER_TaskContext *tc)
579 {
580   struct TunnelState *ts = cls;
581   struct GNUNET_MESH_Tunnel *tunnel;
582
583   ts->destroy_task = GNUNET_SCHEDULER_NO_TASK;
584   GNUNET_assert (NULL != ts->tunnel);
585   tunnel = ts->tunnel;
586   ts->tunnel = NULL;
587   GNUNET_MESH_tunnel_destroy (tunnel);
588   free_tunnel_state (ts);
589 }
590
591
592 /**
593  * Method called whenever a peer has disconnected from the tunnel.
594  *
595  * @param cls closure
596  * @param peer peer identity the tunnel stopped working with
597  */
598 static void
599 tunnel_peer_disconnect_handler (void *cls,
600                                 const struct
601                                 GNUNET_PeerIdentity * peer)
602 {
603   struct TunnelState *ts = cls;
604
605   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606               "Peer %s disconnected from tunnel.\n",
607               GNUNET_i2s (peer));
608   GNUNET_STATISTICS_update (stats,
609                             gettext_noop ("# peers connected to mesh tunnels"),
610                             -1, GNUNET_NO);
611   if (NULL != ts->th)
612   {
613     GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
614     ts->th = NULL;
615   }
616   if (ts->destination.is_service)
617     return; /* hope for reconnect eventually */
618   /* as we are most likely going to change the exit node now,
619      we should just destroy the tunnel entirely... */
620   if (GNUNET_SCHEDULER_NO_TASK == ts->destroy_task)
621     ts->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_tunnel_task, ts);
622 }
623
624
625 /**
626  * Method called whenever a peer has connected to the tunnel.  Notifies
627  * the waiting client that the tunnel is now up.
628  *
629  * @param cls closure
630  * @param peer peer identity the tunnel was created to, NULL on timeout
631  * @param atsi performance data for the connection
632  */
633 static void
634 tunnel_peer_connect_handler (void *cls,
635                              const struct GNUNET_PeerIdentity
636                              * peer,
637                              const struct
638                              GNUNET_ATS_Information * atsi)
639 {
640   struct TunnelState *ts = cls;
641
642   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
643               "Peer %s connected to tunnel.\n",
644               GNUNET_i2s (peer));
645   GNUNET_STATISTICS_update (stats,
646                             gettext_noop ("# peers connected to mesh tunnels"),
647                             1, GNUNET_NO);
648   if (NULL == ts->client)
649     return; /* nothing to do */
650   send_client_reply (ts->client,
651                      ts->request_id,
652                      ts->af,
653                      &ts->destination_ip);
654   GNUNET_SERVER_client_drop (ts->client);
655   ts->client = NULL;
656 }
657
658
659 /**
660  * Send a message from the message queue via mesh.
661  *
662  * @param cls the 'struct TunnelState' with the message queue
663  * @param size number of bytes available in buf
664  * @param buf where to copy the message
665  * @return number of bytes copied to buf
666  */
667 static size_t
668 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
669 {
670   struct TunnelState *ts = cls;
671   struct TunnelMessageQueueEntry *tnq;
672   size_t ret;
673
674   ts->th = NULL;
675   if (NULL == buf)
676     return 0;
677   tnq = ts->tmq_head;
678   GNUNET_assert (NULL != tnq);
679   GNUNET_assert (size >= tnq->len);
680   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
681               "Sending %u bytes via mesh tunnel\n",
682               tnq->len);
683   GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
684                                ts->tmq_tail,
685                                tnq);
686   ts->tmq_length--;
687   memcpy (buf, tnq->msg, tnq->len);
688   ret = tnq->len;
689   GNUNET_free (tnq);
690   if (NULL != (tnq = ts->tmq_head))
691     ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, 
692                                                 GNUNET_NO /* cork */, 
693                                                 GNUNET_TIME_UNIT_FOREVER_REL,
694                                                 NULL, 
695                                                 tnq->len,
696                                                 &send_to_peer_notify_callback,
697                                                 ts);
698   GNUNET_STATISTICS_update (stats,
699                             gettext_noop ("# Bytes given to mesh for transmission"),
700                             ret, GNUNET_NO);
701   return ret;
702 }
703
704
705 /**
706  * Add the given message to the given tunnel and trigger the
707  * transmission process.
708  *
709  * @param tnq message to queue
710  * @param ts tunnel to queue the message for
711  */
712 static void
713 send_to_tunnel (struct TunnelMessageQueueEntry *tnq,
714                 struct TunnelState *ts)
715 {
716   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717               "Queueing %u bytes for transmission via mesh tunnel\n",
718               tnq->len);
719   GNUNET_assert (NULL != ts->tunnel);
720   GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
721                                     ts->tmq_tail,
722                                     tnq);
723   ts->tmq_length++;
724   if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
725   {
726     struct TunnelMessageQueueEntry *dq;
727
728     dq = ts->tmq_head;
729     GNUNET_assert (dq != tnq);
730     GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
731                                  ts->tmq_tail,
732                                  dq);
733     ts->tmq_length--;
734     GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
735     ts->th = NULL;
736     GNUNET_STATISTICS_update (stats,
737                               gettext_noop ("# Bytes dropped in mesh queue (overflow)"),
738                               dq->len, 
739                               GNUNET_NO);
740     GNUNET_free (dq);
741   }
742   if (NULL == ts->th)
743     ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, 
744                                                 GNUNET_NO /* cork */,
745                                                 GNUNET_TIME_UNIT_FOREVER_REL,
746                                                 NULL, 
747                                                 tnq->len,
748                                                 &send_to_peer_notify_callback,
749                                                 ts);
750 }
751
752
753 /**
754  * Initialize the given destination entry's mesh tunnel.
755  *
756  * @param de destination entry for which we need to setup a tunnel
757  * @param client client to notify on successful tunnel setup, or NULL for none
758  * @param client_af address family of the address returned to the client
759  * @param request_id request ID to send in client notification (unused if client is NULL)
760  * @return tunnel state of the tunnel that was created
761  */
762 static struct TunnelState *
763 create_tunnel_to_destination (struct DestinationEntry *de,
764                               struct GNUNET_SERVER_Client *client,
765                               int client_af,
766                               uint64_t request_id)
767 {
768   struct TunnelState *ts;
769
770   GNUNET_STATISTICS_update (stats,
771                             gettext_noop ("# Mesh tunnels created"),
772                             1, GNUNET_NO);
773   GNUNET_assert (NULL == de->ts);
774   ts = GNUNET_malloc (sizeof (struct TunnelState));
775   ts->af = client_af;
776   if (NULL != client)
777   {
778     ts->request_id = request_id;
779     ts->client = client;
780     GNUNET_SERVER_client_keep (client);
781   }
782   ts->destination = *de;
783   ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
784   de->ts = ts;
785   ts->destination_container = de; /* we are referenced from de */
786   ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle,
787                                           ts,
788                                           &tunnel_peer_connect_handler,
789                                           &tunnel_peer_disconnect_handler,
790                                           ts);
791   if (NULL == ts->tunnel)
792   {
793     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
794                 _("Failed to setup mesh tunnel!\n"));
795     if (NULL != client)
796       GNUNET_SERVER_client_drop (client);
797     GNUNET_free (ts);
798     return NULL;
799   }
800   if (de->is_service)
801   {
802     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
803                 "Creating tunnel to peer %s offering service %s\n",
804                 GNUNET_i2s (&de->details.service_destination.target),
805                 GNUNET_h2s (&de->details.service_destination.service_descriptor));
806     GNUNET_MESH_peer_request_connect_add (ts->tunnel,
807                                           &de->details.service_destination.target);  
808   }
809   else
810   {
811     char *policy;
812
813     switch (de->details.exit_destination.af)
814     {
815     case AF_INET:
816     {
817       char address[GNUNET_REGEX_IPV4_REGEXLEN];
818       GNUNET_REGEX_ipv4toregex (&de->details.exit_destination.ip.v4,
819                                 "255.255.255.255", address);
820       GNUNET_asprintf (&policy, "%s%s%s",
821                        GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
822                        "4",
823                        address);
824       break;
825     }
826     case AF_INET6:
827     {
828       char address[GNUNET_REGEX_IPV6_REGEXLEN];
829       GNUNET_REGEX_ipv6toregex (&de->details.exit_destination.ip.v6,
830                                 128, address);
831       GNUNET_asprintf (&policy, "%s%s%s",
832                        GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
833                        "6",
834                        address);
835       break;
836     }
837     default:
838       GNUNET_assert (0);
839       break;
840     }
841
842     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requesting connect by string: %s\n", policy);
843
844     GNUNET_MESH_peer_request_connect_by_string (ts->tunnel, policy);
845     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
846                 "Creating tunnel to exit peer for policy `%s'\n",
847                 policy);
848     GNUNET_free (policy);
849   }
850   return ts;
851 }
852
853
854 /**
855  * We have too many active tunnels.  Clean up the oldest tunnel.
856  *
857  * @param except tunnel that must NOT be cleaned up, even if it is the oldest
858  */
859 static void
860 expire_tunnel (struct TunnelState *except)
861 {
862   struct TunnelState *ts;
863
864   ts = GNUNET_CONTAINER_heap_peek (tunnel_heap);
865   GNUNET_assert (NULL != ts);
866   if (except == ts)
867     return; /* can't do this */
868   free_tunnel_state (ts);
869 }
870
871
872 /**
873  * Route a packet via mesh to the given destination.  
874  *
875  * @param destination description of the destination
876  * @param af address family on this end (AF_INET or AF_INET6)
877  * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
878  * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
879  * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
880  * @param payload payload of the packet after the IP header
881  * @param payload_length number of bytes in payload
882  */
883 static void
884 route_packet (struct DestinationEntry *destination,
885               int af,
886               uint8_t protocol,
887               const void *source_ip,
888               const void *destination_ip,
889               const void *payload,
890               size_t payload_length)
891 {
892   struct GNUNET_HashCode key;
893   struct TunnelState *ts;
894   struct TunnelMessageQueueEntry *tnq;
895   size_t alen;
896   size_t mlen;
897   int is_new;
898   const struct GNUNET_TUN_UdpHeader *udp;
899   const struct GNUNET_TUN_TcpHeader *tcp;
900   const struct GNUNET_TUN_IcmpHeader *icmp;
901   uint16_t source_port;
902   uint16_t destination_port;
903
904   switch (protocol)
905   {
906   case IPPROTO_UDP:
907     {
908       if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
909       {
910         /* blame kernel? */
911         GNUNET_break (0);
912         return;
913       }
914       tcp = NULL; /* make compiler happy */
915       icmp = NULL;  /* make compiler happy */
916       udp = payload;
917       if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
918       {
919         GNUNET_break_op (0);
920         return;
921       }
922       source_port = ntohs (udp->source_port);
923       destination_port = ntohs (udp->destination_port);
924       get_tunnel_key_from_ips (af,
925                                IPPROTO_UDP,
926                                source_ip,
927                                source_port,
928                                destination_ip,
929                                destination_port,
930                                &key);
931     }
932     break;
933   case IPPROTO_TCP:
934     {
935       if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
936       {
937         /* blame kernel? */
938         GNUNET_break (0);
939         return;
940       }      
941       udp = NULL; /* make compiler happy */
942       icmp = NULL;  /* make compiler happy */
943       tcp = payload;
944       if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
945       {
946         GNUNET_break_op (0);
947         return;
948       }
949       source_port = ntohs (tcp->source_port);
950       destination_port = ntohs (tcp->destination_port);
951       get_tunnel_key_from_ips (af,
952                                IPPROTO_TCP,
953                                source_ip,
954                                source_port,
955                                destination_ip,
956                                destination_port,
957                                &key);
958     }
959     break;
960   case IPPROTO_ICMP:  
961   case IPPROTO_ICMPV6:  
962     {
963       if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
964       {
965         GNUNET_break (0);
966         return;
967       }
968       if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
969       {
970         /* blame kernel? */
971         GNUNET_break (0);
972         return;
973       }
974       tcp = NULL; /* make compiler happy */
975       udp = NULL;  /* make compiler happy */
976       icmp = payload;
977       source_port = 0;
978       destination_port = 0;
979       get_tunnel_key_from_ips (af,
980                                protocol,
981                                source_ip,
982                                0,
983                                destination_ip,
984                                0,
985                                &key);
986     }
987     break;
988   default:
989     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
990                 _("Protocol %u not supported, dropping\n"),
991                 (unsigned int) protocol);
992     return;
993   }
994   if (! destination->is_service)
995   {  
996     switch (destination->details.exit_destination.af)
997     {
998     case AF_INET:
999       alen = sizeof (struct in_addr);
1000      break;
1001     case AF_INET6:
1002       alen = sizeof (struct in6_addr);
1003       break;
1004     default:
1005       alen = 0;
1006       GNUNET_assert (0);
1007     }
1008
1009     {
1010       char sbuf[INET6_ADDRSTRLEN];
1011       char dbuf[INET6_ADDRSTRLEN];
1012       char xbuf[INET6_ADDRSTRLEN];
1013       
1014       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1015                   "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n",
1016                   (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1017                   inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1018                   source_port,
1019                   inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1020                   destination_port,
1021                   inet_ntop (destination->details.exit_destination.af,
1022                              &destination->details.exit_destination.ip,
1023                              xbuf, sizeof (xbuf)),
1024                   destination_port);
1025     }
1026   }
1027   else
1028   {
1029     /* make compiler happy */
1030     alen = 0;
1031     {
1032       char sbuf[INET6_ADDRSTRLEN];
1033       char dbuf[INET6_ADDRSTRLEN];
1034       
1035       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1036                   "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n",
1037                   (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1038                   inet_ntop (af, source_ip, sbuf, sizeof (sbuf)),
1039                   source_port,
1040                   inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)),
1041                   destination_port,
1042                   GNUNET_h2s (&destination->details.service_destination.service_descriptor),
1043                   GNUNET_i2s (&destination->details.service_destination.target));
1044     }
1045
1046   }
1047
1048   /* see if we have an existing tunnel for this destination */
1049   ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map,
1050                                           &key);
1051   if (NULL == ts)
1052   {
1053     /* need to either use the existing tunnel from the destination (if still
1054        available) or create a fresh one */
1055     is_new = GNUNET_YES;
1056     if (NULL == destination->ts)
1057       ts = create_tunnel_to_destination (destination, NULL, af, 0);
1058     else
1059       ts = destination->ts;
1060     if (NULL == ts)
1061       return;
1062     destination->ts = NULL;
1063     ts->destination_container = NULL; /* no longer 'contained' */
1064     /* now bind existing "unbound" tunnel to our IP/port tuple */
1065     ts->protocol = protocol;
1066     ts->af = af; 
1067     if (af == AF_INET)
1068     {
1069       ts->source_ip.v4 = * (const struct in_addr *) source_ip;
1070       ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
1071     }
1072     else
1073     {
1074       ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
1075       ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
1076     }
1077     ts->source_port = source_port;
1078     ts->destination_port = destination_port;
1079     ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap,
1080                                                   ts,
1081                                                   GNUNET_TIME_absolute_get ().abs_value);
1082     GNUNET_assert (GNUNET_YES ==
1083                    GNUNET_CONTAINER_multihashmap_put (tunnel_map,
1084                                                       &key,
1085                                                       ts,
1086                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 
1087     GNUNET_STATISTICS_update (stats,
1088                               gettext_noop ("# Active tunnels"),
1089                               1, GNUNET_NO);
1090     while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings)
1091       expire_tunnel (ts);
1092   }
1093   else
1094   {
1095     is_new = GNUNET_NO;
1096     GNUNET_CONTAINER_heap_update_cost (tunnel_heap, 
1097                                        ts->heap_node,
1098                                        GNUNET_TIME_absolute_get ().abs_value);
1099   }
1100   GNUNET_assert (NULL != ts->tunnel);
1101   
1102   /* send via tunnel */
1103   switch (protocol)
1104   {
1105   case IPPROTO_UDP:
1106     if (destination->is_service)
1107     {
1108       struct GNUNET_EXIT_UdpServiceMessage *usm;
1109
1110       mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) + 
1111         payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1112       if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1113       {
1114         GNUNET_break (0);
1115         return;
1116       }
1117       tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1118       tnq->len = mlen;
1119       tnq->msg = &tnq[1];
1120       usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1121       usm->header.size = htons ((uint16_t) mlen);
1122       usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1123       /* if the source port is below 32000, we assume it has a special
1124          meaning; if not, we pick a random port (this is a heuristic) */
1125       usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1126       usm->destination_port = udp->destination_port;
1127       usm->service_descriptor = destination->details.service_destination.service_descriptor;
1128       memcpy (&usm[1],
1129               &udp[1],
1130               payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1131     }
1132     else
1133     {
1134       struct GNUNET_EXIT_UdpInternetMessage *uim;
1135       struct in_addr *ip4dst;
1136       struct in6_addr *ip6dst;
1137       void *payload;
1138
1139       mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) + 
1140         alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1141       if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1142       {
1143         GNUNET_break (0);
1144         return;
1145       }
1146       tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + 
1147                            mlen);
1148       tnq->len = mlen;
1149       tnq->msg = &tnq[1];
1150       uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1151       uim->header.size = htons ((uint16_t) mlen);
1152       uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET); 
1153       uim->af = htonl (destination->details.exit_destination.af);
1154       uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1155       uim->destination_port = udp->destination_port;
1156       switch (destination->details.exit_destination.af)
1157       {
1158       case AF_INET:
1159         ip4dst = (struct in_addr *) &uim[1];
1160         *ip4dst = destination->details.exit_destination.ip.v4;
1161         payload = &ip4dst[1];
1162         break;
1163       case AF_INET6:
1164         ip6dst = (struct in6_addr *) &uim[1];
1165         *ip6dst = destination->details.exit_destination.ip.v6;
1166         payload = &ip6dst[1];
1167         break;
1168       default:
1169         GNUNET_assert (0);
1170       }
1171       memcpy (payload,
1172               &udp[1],
1173               payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1174     }
1175     break;
1176   case IPPROTO_TCP:
1177     if (is_new)
1178     {
1179       if (destination->is_service)
1180       {
1181         struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1182
1183         mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) + 
1184           payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1185         if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1186         {
1187           GNUNET_break (0);
1188           return;
1189         }
1190         tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1191         tnq->len = mlen;
1192         tnq->msg = &tnq[1];
1193         tsm = (struct  GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1194         tsm->header.size = htons ((uint16_t) mlen);
1195         tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1196         tsm->reserved = htonl (0);
1197         tsm->service_descriptor = destination->details.service_destination.service_descriptor;
1198         tsm->tcp_header = *tcp;
1199         memcpy (&tsm[1],
1200                 &tcp[1],
1201                 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1202       }
1203       else
1204       {
1205         struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1206         struct in_addr *ip4dst;
1207         struct in6_addr *ip6dst;
1208         void *payload;
1209
1210         mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) + 
1211           alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1212         if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1213         {
1214           GNUNET_break (0);
1215           return;
1216         }
1217         tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1218         tnq->len = mlen;
1219         tnq->msg = &tnq[1];
1220         tim = (struct  GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1221         tim->header.size = htons ((uint16_t) mlen);
1222         tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1223         tim->af = htonl (destination->details.exit_destination.af);     
1224         tim->tcp_header = *tcp;
1225         switch (destination->details.exit_destination.af)
1226         {
1227         case AF_INET:
1228           ip4dst = (struct in_addr *) &tim[1];
1229           *ip4dst = destination->details.exit_destination.ip.v4;
1230           payload = &ip4dst[1];
1231           break;
1232         case AF_INET6:
1233           ip6dst = (struct in6_addr *) &tim[1];
1234           *ip6dst = destination->details.exit_destination.ip.v6;
1235           payload = &ip6dst[1];
1236           break;
1237         default:
1238           GNUNET_assert (0);
1239         }
1240         memcpy (payload,
1241                 &tcp[1],
1242                 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1243       }
1244     }
1245     else
1246     {
1247       struct GNUNET_EXIT_TcpDataMessage *tdm;
1248
1249       mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + 
1250         payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1251       if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1252       {
1253         GNUNET_break (0);
1254         return;
1255       }
1256       tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1257       tnq->len = mlen;
1258       tnq->msg = &tnq[1];
1259       tdm = (struct  GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1260       tdm->header.size = htons ((uint16_t) mlen);
1261       tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1262       tdm->reserved = htonl (0);
1263       tdm->tcp_header = *tcp;
1264       memcpy (&tdm[1],
1265               &tcp[1],
1266               payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1267      }
1268     break;
1269   case IPPROTO_ICMP:
1270   case IPPROTO_ICMPV6:
1271     if (destination->is_service)
1272     {
1273       struct GNUNET_EXIT_IcmpServiceMessage *ism;
1274
1275       mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) + 
1276         payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1277       if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1278       {
1279         GNUNET_break (0);
1280         return;
1281       }
1282       tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen);
1283       tnq->msg = &tnq[1];
1284       ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1285       ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1286       ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1287       ism->service_descriptor = destination->details.service_destination.service_descriptor;
1288       ism->icmp_header = *icmp;
1289       /* ICMP protocol translation will be done by the receiver (as we don't know
1290          the target AF); however, we still need to possibly discard the payload
1291          depending on the ICMP type */
1292       switch (af)
1293       {
1294       case AF_INET:
1295         switch (icmp->type)
1296         {
1297         case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1298         case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1299           break;
1300         case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1301         case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1302         case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1303           /* throw away ICMP payload, won't be useful for the other side anyway */
1304           payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); 
1305           break;
1306         default:
1307           GNUNET_STATISTICS_update (stats,
1308                                     gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
1309                                     1, GNUNET_NO);
1310           return;
1311         }
1312         /* end of AF_INET */
1313         break;
1314       case AF_INET6:
1315         switch (icmp->type)
1316         {
1317         case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1318         case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1319         case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1320         case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1321           /* throw away ICMP payload, won't be useful for the other side anyway */
1322           payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); 
1323           break;
1324         case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1325         case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1326           break;
1327         default:
1328           GNUNET_STATISTICS_update (stats,
1329                                     gettext_noop ("# ICMPv6 packets dropped (not allowed)"),
1330                                     1, GNUNET_NO);
1331           return;
1332         }       
1333         /* end of AF_INET6 */
1334         break;
1335       default:
1336         GNUNET_assert (0);
1337         break;
1338       }
1339
1340       /* update length calculations, as payload_length may have changed */
1341       mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) + 
1342         alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);      
1343       tnq->len = mlen;
1344       ism->header.size = htons ((uint16_t) mlen);
1345       /* finally, copy payload (if there is any left...) */
1346       memcpy (&ism[1],
1347               &icmp[1],
1348               payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1349     }
1350     else
1351     {
1352       struct GNUNET_EXIT_IcmpInternetMessage *iim;
1353       struct in_addr *ip4dst;
1354       struct in6_addr *ip6dst;
1355       void *payload;
1356
1357       mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) + 
1358         alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1359       if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1360       {
1361         GNUNET_break (0);
1362         return;
1363       }
1364       tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + 
1365                            mlen);
1366       tnq->msg = &tnq[1];
1367       iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1368       iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET); 
1369       iim->icmp_header = *icmp;
1370       /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1371          and throw away ICMP payload depending on ICMP message type */
1372       switch (af)
1373       {
1374       case AF_INET:
1375         switch (icmp->type)
1376         {
1377         case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:      
1378           if (destination->details.exit_destination.af == AF_INET6)
1379             iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1380           break;
1381         case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:    
1382           if (destination->details.exit_destination.af == AF_INET6)
1383             iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1384           break;
1385         case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1386           if (destination->details.exit_destination.af == AF_INET6)
1387             iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1388           /* throw away IP-payload, exit will have to make it up anyway */
1389           payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1390           break;
1391         case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: 
1392           if (destination->details.exit_destination.af == AF_INET6)
1393             iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1394           /* throw away IP-payload, exit will have to make it up anyway */
1395           payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1396           break;
1397         case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1398           if (destination->details.exit_destination.af == AF_INET6)
1399             {
1400               GNUNET_STATISTICS_update (stats,
1401                                         gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1402                                         1, GNUNET_NO);
1403               GNUNET_free (tnq);
1404               return;
1405             }
1406           /* throw away IP-payload, exit will have to make it up anyway */
1407           payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1408           break;
1409         default:
1410           GNUNET_STATISTICS_update (stats,
1411                                     gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1412                                     1, GNUNET_NO);
1413           GNUNET_free (tnq);        
1414           return;
1415         }
1416         /* end of AF_INET */
1417         break;
1418       case AF_INET6:
1419         switch (icmp->type)
1420           {
1421           case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1422             if (destination->details.exit_destination.af == AF_INET6)
1423               iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1424             /* throw away IP-payload, exit will have to make it up anyway */
1425             payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1426             break;
1427           case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1428             if (destination->details.exit_destination.af == AF_INET)
1429               iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1430             /* throw away IP-payload, exit will have to make it up anyway */
1431             payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1432             break;
1433           case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1434             if (destination->details.exit_destination.af == AF_INET)
1435             {
1436               GNUNET_STATISTICS_update (stats,
1437                                         gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1438                                         1, GNUNET_NO);
1439               GNUNET_free (tnq);
1440               return;
1441             }
1442             /* throw away IP-payload, exit will have to make it up anyway */
1443             payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1444             break;
1445           case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1446             if (destination->details.exit_destination.af == AF_INET)
1447             {
1448               GNUNET_STATISTICS_update (stats,
1449                                         gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1450                                         1, GNUNET_NO);
1451               GNUNET_free (tnq);
1452               return;
1453             }
1454             /* throw away IP-payload, exit will have to make it up anyway */
1455             payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1456             break;
1457           case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1458             if (destination->details.exit_destination.af == AF_INET)
1459               iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1460             break;
1461           case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1462             if (destination->details.exit_destination.af == AF_INET)
1463               iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1464             break;
1465           default:
1466             GNUNET_STATISTICS_update (stats,
1467                                       gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1468                                       1, GNUNET_NO);
1469             GNUNET_free (tnq);      
1470             return;
1471           }
1472         /* end of AF_INET6 */
1473         break;
1474       default:
1475         GNUNET_assert (0);
1476       } 
1477       /* update length calculations, as payload_length may have changed */
1478       mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) + 
1479         alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);      
1480       tnq->len = mlen;
1481       iim->header.size = htons ((uint16_t) mlen);
1482
1483       /* need to tell destination ICMP protocol family! */
1484       iim->af = htonl (destination->details.exit_destination.af);
1485       switch (destination->details.exit_destination.af)
1486       {
1487       case AF_INET:
1488         ip4dst = (struct in_addr *) &iim[1];
1489         *ip4dst = destination->details.exit_destination.ip.v4;
1490         payload = &ip4dst[1];
1491         break;
1492       case AF_INET6:
1493         ip6dst = (struct in6_addr *) &iim[1];
1494         *ip6dst = destination->details.exit_destination.ip.v6;
1495         payload = &ip6dst[1];
1496         break;
1497       default:
1498         GNUNET_assert (0);
1499       }
1500       memcpy (payload,
1501               &icmp[1],
1502               payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1503     }
1504     break;
1505   default:
1506     /* not supported above, how can we get here !? */
1507     GNUNET_assert (0);
1508     break;
1509   }
1510   send_to_tunnel (tnq, ts);
1511 }
1512
1513
1514 /**
1515  * Receive packets from the helper-process (someone send to the local
1516  * virtual tunnel interface).  Find the destination mapping, and if it
1517  * exists, identify the correct MESH tunnel (or possibly create it)
1518  * and forward the packet.
1519  *
1520  * @param cls closure, NULL
1521  * @param client NULL
1522  * @param message message we got from the client (VPN tunnel interface)
1523  */
1524 static int
1525 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
1526                const struct GNUNET_MessageHeader *message)
1527 {
1528   const struct GNUNET_TUN_Layer2PacketHeader *tun;
1529   size_t mlen;
1530   struct GNUNET_HashCode key;
1531   struct DestinationEntry *de;
1532
1533   GNUNET_STATISTICS_update (stats,
1534                             gettext_noop ("# Packets received from TUN interface"),
1535                             1, GNUNET_NO);
1536   mlen = ntohs (message->size);
1537   if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
1538        (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
1539   {
1540     GNUNET_break (0);
1541     return GNUNET_OK;
1542   }
1543   tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1544   mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
1545   switch (ntohs (tun->proto))
1546   {
1547   case ETH_P_IPV6:
1548     {
1549       const struct GNUNET_TUN_IPv6Header *pkt6;
1550       
1551       if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
1552       {
1553         /* blame kernel */
1554         GNUNET_break (0);
1555         return GNUNET_OK;
1556       }
1557       pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1558       get_destination_key_from_ip (AF_INET6,
1559                                    &pkt6->destination_address,
1560                                    &key);
1561       de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1562       /* FIXME: do we need to guard against hash collision? 
1563          (if so, we need to also store the local destination IP in the
1564          destination entry and then compare here; however, the risk
1565          of collision seems minimal AND the impact is unlikely to be
1566          super-problematic as well... */
1567       if (NULL == de)
1568       {
1569         char buf[INET6_ADDRSTRLEN];
1570         
1571         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1572                     _("Packet received for unmapped destination `%s' (dropping it)\n"),
1573                     inet_ntop (AF_INET6,
1574                                &pkt6->destination_address,
1575                                buf,
1576                                sizeof (buf)));
1577         return GNUNET_OK;
1578       }
1579       route_packet (de,
1580                     AF_INET6,
1581                     pkt6->next_header,
1582                     &pkt6->source_address,                  
1583                     &pkt6->destination_address,             
1584                     &pkt6[1],
1585                     mlen - sizeof (struct GNUNET_TUN_IPv6Header));
1586     }
1587     break;
1588   case ETH_P_IPV4:
1589     {
1590       struct GNUNET_TUN_IPv4Header *pkt4;
1591
1592       if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
1593       {
1594         /* blame kernel */
1595         GNUNET_break (0);
1596         return GNUNET_OK;
1597       }
1598       pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1599       get_destination_key_from_ip (AF_INET,
1600                                    &pkt4->destination_address,
1601                                    &key);
1602       de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
1603       /* FIXME: do we need to guard against hash collision? 
1604          (if so, we need to also store the local destination IP in the
1605          destination entry and then compare here; however, the risk
1606          of collision seems minimal AND the impact is unlikely to be
1607          super-problematic as well... */
1608       if (NULL == de)
1609       {
1610         char buf[INET_ADDRSTRLEN];
1611         
1612         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1613                     _("Packet received for unmapped destination `%s' (dropping it)\n"),
1614                     inet_ntop (AF_INET,
1615                                &pkt4->destination_address,
1616                                buf,
1617                                sizeof (buf)));
1618         return GNUNET_OK;
1619       }
1620       if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1621       {
1622         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1623                     _("Received IPv4 packet with options (dropping it)\n"));                
1624         return GNUNET_OK;
1625       }
1626       route_packet (de,
1627                     AF_INET,
1628                     pkt4->protocol,
1629                     &pkt4->source_address,                  
1630                     &pkt4->destination_address,             
1631                     &pkt4[1],
1632                     mlen - sizeof (struct GNUNET_TUN_IPv4Header));
1633     }
1634     break;
1635   default:
1636     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1637                 _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
1638                 (unsigned int) ntohs (tun->proto));
1639     break;
1640   }
1641   return GNUNET_OK;
1642 }
1643
1644
1645 /**
1646  * Synthesize a plausible ICMP payload for an ICMP error
1647  * response on the given tunnel.
1648  *
1649  * @param ts tunnel information
1650  * @param ipp IPv4 header to fill in (ICMP payload)
1651  * @param udp "UDP" header to fill in (ICMP payload); might actually
1652  *            also be the first 8 bytes of the TCP header
1653  */
1654 static void
1655 make_up_icmpv4_payload (struct TunnelState *ts,
1656                         struct GNUNET_TUN_IPv4Header *ipp,
1657                         struct GNUNET_TUN_UdpHeader *udp)
1658 {
1659   GNUNET_TUN_initialize_ipv4_header (ipp,
1660                                      ts->protocol,
1661                                      sizeof (struct GNUNET_TUN_TcpHeader),
1662                                      &ts->source_ip.v4,
1663                                      &ts->destination_ip.v4);
1664   udp->source_port = htons (ts->source_port);
1665   udp->destination_port = htons (ts->destination_port);
1666   udp->len = htons (0);
1667   udp->crc = htons (0);
1668 }
1669
1670
1671 /**
1672  * Synthesize a plausible ICMP payload for an ICMP error
1673  * response on the given tunnel.
1674  *
1675  * @param ts tunnel information
1676  * @param ipp IPv6 header to fill in (ICMP payload)
1677  * @param udp "UDP" header to fill in (ICMP payload); might actually
1678  *            also be the first 8 bytes of the TCP header
1679  */
1680 static void
1681 make_up_icmpv6_payload (struct TunnelState *ts,
1682                         struct GNUNET_TUN_IPv6Header *ipp,
1683                         struct GNUNET_TUN_UdpHeader *udp)
1684 {
1685   GNUNET_TUN_initialize_ipv6_header (ipp,
1686                                      ts->protocol,
1687                                      sizeof (struct GNUNET_TUN_TcpHeader),
1688                                      &ts->source_ip.v6,
1689                                      &ts->destination_ip.v6);
1690   udp->source_port = htons (ts->source_port);
1691   udp->destination_port = htons (ts->destination_port);
1692   udp->len = htons (0);
1693   udp->crc = htons (0);
1694 }
1695
1696
1697 /**
1698  * We got an ICMP packet back from the MESH tunnel.  Pass it on to the
1699  * local virtual interface via the helper.
1700  *
1701  * @param cls closure, NULL
1702  * @param tunnel connection to the other end
1703  * @param tunnel_ctx pointer to our 'struct TunnelState *'
1704  * @param sender who sent the message
1705  * @param message the actual message
1706  * @param atsi performance data for the connection
1707  * @return GNUNET_OK to keep the connection open,
1708  *         GNUNET_SYSERR to close it (signal serious error)
1709  */ 
1710 static int
1711 receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1712                    void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
1713                    const struct GNUNET_MessageHeader *message,
1714                    const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1715 {
1716   struct TunnelState *ts = *tunnel_ctx;
1717   const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1718   size_t mlen;
1719
1720   GNUNET_STATISTICS_update (stats,
1721                             gettext_noop ("# ICMP packets received from mesh"),
1722                             1, GNUNET_NO);
1723   mlen = ntohs (message->size);
1724   if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1725   {
1726     GNUNET_break_op (0);
1727     return GNUNET_SYSERR;
1728   }
1729   if (NULL == ts->heap_node)
1730   {
1731     GNUNET_break_op (0);
1732     return GNUNET_SYSERR;
1733   }
1734   if (AF_UNSPEC == ts->af)
1735   {
1736     GNUNET_break_op (0);
1737     return GNUNET_SYSERR;
1738   }
1739   i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1740   mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1741   {
1742     char sbuf[INET6_ADDRSTRLEN];
1743     char dbuf[INET6_ADDRSTRLEN];
1744     
1745     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1746                 "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n",
1747                 (unsigned int) mlen,
1748                 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1749                 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1750   }
1751   switch (ts->af)
1752   {
1753   case AF_INET:
1754     {
1755       size_t size = sizeof (struct GNUNET_TUN_IPv4Header) 
1756         + sizeof (struct GNUNET_TUN_IcmpHeader) 
1757         + sizeof (struct GNUNET_MessageHeader) +
1758         sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1759         mlen;
1760       {
1761         /* reserve some extra space in case we have an ICMP type here where
1762            we will need to make up the payload ourselves */
1763         char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1764         struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1765         struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1766         struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1767         struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1768         msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1769         tun->flags = htons (0);
1770         tun->proto = htons (ETH_P_IPV4);
1771         GNUNET_TUN_initialize_ipv4_header (ipv4,
1772                                            IPPROTO_ICMP,
1773                                            sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1774                                            &ts->destination_ip.v4,
1775                                            &ts->source_ip.v4);
1776         *icmp = i2v->icmp_header;
1777         memcpy (&icmp[1],
1778                 &i2v[1],
1779                 mlen);
1780         /* For some ICMP types, we need to adjust (make up) the payload here. 
1781            Also, depending on the AF used on the other side, we have to 
1782            do ICMP PT (translate ICMP types) */
1783         switch (ntohl (i2v->af))
1784         {
1785         case AF_INET:     
1786           switch (icmp->type)
1787           {
1788           case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1789           case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1790             break;
1791           case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1792           case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1793           case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:         
1794             {
1795               struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1796               struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1797               
1798               if (mlen != 0)
1799                 {
1800                   /* sender did not strip ICMP payload? */
1801                   GNUNET_break_op (0);
1802                   return GNUNET_SYSERR;
1803                 }
1804               size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1805               GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1806               make_up_icmpv4_payload (ts, ipp, udp);
1807             }
1808             break;
1809           default:
1810             GNUNET_break_op (0);
1811             GNUNET_STATISTICS_update (stats,
1812                                       gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1813                                       1, GNUNET_NO);
1814             return GNUNET_SYSERR;
1815           }
1816           /* end AF_INET */
1817           break;
1818         case AF_INET6:
1819           /* ICMP PT 6-to-4 and possibly making up payloads */
1820           switch (icmp->type)
1821           {
1822           case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1823             icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1824             {
1825               struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1826               struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1827               
1828               if (mlen != 0)
1829                 {
1830                   /* sender did not strip ICMP payload? */
1831                   GNUNET_break_op (0);
1832                   return GNUNET_SYSERR;
1833                 }
1834               size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1835               GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1836               make_up_icmpv4_payload (ts, ipp, udp);
1837             }
1838             break;
1839           case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1840             icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1841             {
1842               struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1843               struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1844               
1845               if (mlen != 0)
1846                 {
1847                   /* sender did not strip ICMP payload? */
1848                   GNUNET_break_op (0);
1849                   return GNUNET_SYSERR;
1850                 }
1851               size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1852               GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1853               make_up_icmpv4_payload (ts, ipp, udp);
1854             }
1855             break;
1856           case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1857           case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1858             GNUNET_STATISTICS_update (stats,
1859                                       gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1860                                       1, GNUNET_NO);
1861             return GNUNET_OK;
1862           case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1863             icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1864             break;
1865           case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1866             icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1867             break;
1868           default:
1869             GNUNET_break_op (0);
1870             GNUNET_STATISTICS_update (stats,
1871                                       gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1872                                       1, GNUNET_NO);
1873             return GNUNET_SYSERR;
1874           }
1875           /* end AF_INET6 */
1876           break;
1877         default:
1878           GNUNET_break_op (0);
1879           return GNUNET_SYSERR;
1880         }       
1881         msg->size = htons (size);
1882         GNUNET_TUN_calculate_icmp_checksum (icmp,
1883                                             &i2v[1],
1884                                             mlen);
1885         (void) GNUNET_HELPER_send (helper_handle,
1886                                    msg,
1887                                    GNUNET_YES,
1888                                    NULL, NULL);
1889       }
1890     }
1891     break;
1892   case AF_INET6:
1893     {
1894       size_t size = sizeof (struct GNUNET_TUN_IPv6Header) 
1895         + sizeof (struct GNUNET_TUN_IcmpHeader) 
1896         + sizeof (struct GNUNET_MessageHeader) +
1897         sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1898         mlen;
1899       {
1900         char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1901         struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1902         struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1903         struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1904         struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1905         msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1906         tun->flags = htons (0);
1907         tun->proto = htons (ETH_P_IPV6);
1908         GNUNET_TUN_initialize_ipv6_header (ipv6,
1909                                            IPPROTO_ICMPV6,
1910                                            sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1911                                            &ts->destination_ip.v6,
1912                                            &ts->source_ip.v6);
1913         *icmp = i2v->icmp_header;
1914         memcpy (&icmp[1],
1915                 &i2v[1],
1916                 mlen);
1917
1918         /* For some ICMP types, we need to adjust (make up) the payload here. 
1919            Also, depending on the AF used on the other side, we have to 
1920            do ICMP PT (translate ICMP types) */
1921         switch (ntohl (i2v->af))
1922         {
1923         case AF_INET:     
1924           /* ICMP PT 4-to-6 and possibly making up payloads */
1925           switch (icmp->type)
1926           {
1927           case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1928             icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1929             break;
1930           case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1931             icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1932             break;
1933           case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1934             icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1935             {
1936               struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1937               struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1938               
1939               if (mlen != 0)
1940                 {
1941                   /* sender did not strip ICMP payload? */
1942                   GNUNET_break_op (0);
1943                   return GNUNET_SYSERR;
1944                 }
1945               size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1946               GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1947               make_up_icmpv6_payload (ts, ipp, udp);
1948             }
1949             break;
1950           case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:         
1951             icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1952             {
1953               struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1954               struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1955               
1956               if (mlen != 0)
1957                 {
1958                   /* sender did not strip ICMP payload? */
1959                   GNUNET_break_op (0);
1960                   return GNUNET_SYSERR;
1961                 }
1962               size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1963               GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1964               make_up_icmpv6_payload (ts, ipp, udp);
1965             }
1966             break;
1967           case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1968             GNUNET_STATISTICS_update (stats,
1969                                       gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1970                                       1, GNUNET_NO);        
1971             return GNUNET_OK;
1972           default:
1973             GNUNET_break_op (0);
1974             GNUNET_STATISTICS_update (stats,
1975                                       gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1976                                       1, GNUNET_NO);
1977             return GNUNET_SYSERR;
1978           }
1979           /* end AF_INET */
1980           break;
1981         case AF_INET6:
1982           switch (icmp->type)
1983           {
1984           case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1985           case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1986           case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1987           case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1988             {
1989               struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1990               struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1991               
1992               if (mlen != 0)
1993                 {
1994                   /* sender did not strip ICMP payload? */
1995                   GNUNET_break_op (0);
1996                   return GNUNET_SYSERR;
1997                 }
1998               size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1999               GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2000               make_up_icmpv6_payload (ts, ipp, udp);
2001             }
2002             break;
2003           case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2004             break;
2005           default:
2006             GNUNET_break_op (0);
2007             GNUNET_STATISTICS_update (stats,
2008                                       gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2009                                       1, GNUNET_NO);
2010             return GNUNET_SYSERR;
2011           }
2012           /* end AF_INET6 */
2013           break;
2014         default:
2015           GNUNET_break_op (0);
2016           return GNUNET_SYSERR;
2017         }
2018         msg->size = htons (size);
2019         GNUNET_TUN_calculate_icmp_checksum (icmp,
2020                                             &i2v[1], mlen);
2021         (void) GNUNET_HELPER_send (helper_handle,
2022                                    msg,
2023                                    GNUNET_YES,
2024                                    NULL, NULL);
2025       }
2026     }
2027     break;
2028   default:
2029     GNUNET_assert (0);
2030   }
2031   GNUNET_CONTAINER_heap_update_cost (tunnel_heap, 
2032                                      ts->heap_node,
2033                                      GNUNET_TIME_absolute_get ().abs_value);
2034   return GNUNET_OK;
2035 }
2036
2037
2038 /**
2039  * We got a UDP packet back from the MESH tunnel.  Pass it on to the
2040  * local virtual interface via the helper.
2041  *
2042  * @param cls closure, NULL
2043  * @param tunnel connection to the other end
2044  * @param tunnel_ctx pointer to our 'struct TunnelState *'
2045  * @param sender who sent the message
2046  * @param message the actual message
2047  * @param atsi performance data for the connection
2048  * @return GNUNET_OK to keep the connection open,
2049  *         GNUNET_SYSERR to close it (signal serious error)
2050  */ 
2051 static int
2052 receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2053                   void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender,
2054                   const struct GNUNET_MessageHeader *message,
2055                   const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2056 {
2057   struct TunnelState *ts = *tunnel_ctx;
2058   const struct GNUNET_EXIT_UdpReplyMessage *reply;
2059   size_t mlen;
2060
2061   GNUNET_STATISTICS_update (stats,
2062                             gettext_noop ("# UDP packets received from mesh"),
2063                             1, GNUNET_NO);
2064   mlen = ntohs (message->size);
2065   if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2066   {
2067     GNUNET_break_op (0);
2068     return GNUNET_SYSERR;
2069   }
2070   if (NULL == ts->heap_node)
2071   {
2072     GNUNET_break_op (0);
2073     return GNUNET_SYSERR;
2074   }
2075   if (AF_UNSPEC == ts->af)
2076   {
2077     GNUNET_break_op (0);
2078     return GNUNET_SYSERR;
2079   }
2080   reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2081   mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2082   {
2083     char sbuf[INET6_ADDRSTRLEN];
2084     char dbuf[INET6_ADDRSTRLEN];
2085     
2086     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2087                 "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2088                 (unsigned int) mlen,
2089                 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2090                 ts->destination_port,
2091                 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2092                 ts->source_port);
2093   }
2094   switch (ts->af)
2095   {
2096   case AF_INET:
2097     {
2098       size_t size = sizeof (struct GNUNET_TUN_IPv4Header) 
2099         + sizeof (struct GNUNET_TUN_UdpHeader) 
2100         + sizeof (struct GNUNET_MessageHeader) +
2101         sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2102         mlen;
2103       {
2104         char buf[size] GNUNET_ALIGN;
2105         struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2106         struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2107         struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2108         struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2109         msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2110         msg->size = htons (size);
2111         tun->flags = htons (0);
2112         tun->proto = htons (ETH_P_IPV4);
2113         GNUNET_TUN_initialize_ipv4_header (ipv4,
2114                                            IPPROTO_UDP,
2115                                            sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2116                                            &ts->destination_ip.v4,
2117                                            &ts->source_ip.v4);
2118         if (0 == ntohs (reply->source_port))
2119           udp->source_port = htons (ts->destination_port);
2120         else
2121           udp->source_port = reply->source_port;
2122         if (0 == ntohs (reply->destination_port))
2123           udp->destination_port = htons (ts->source_port);
2124         else
2125           udp->destination_port = reply->destination_port;
2126         udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2127         GNUNET_TUN_calculate_udp4_checksum (ipv4,
2128                                             udp,
2129                                             &reply[1],
2130                                             mlen);
2131         memcpy (&udp[1],
2132                 &reply[1],
2133                 mlen);
2134         (void) GNUNET_HELPER_send (helper_handle,
2135                                    msg,
2136                                    GNUNET_YES,
2137                                    NULL, NULL);
2138       }
2139     }
2140     break;
2141   case AF_INET6:
2142     {
2143       size_t size = sizeof (struct GNUNET_TUN_IPv6Header) 
2144         + sizeof (struct GNUNET_TUN_UdpHeader) 
2145         + sizeof (struct GNUNET_MessageHeader) +
2146         sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2147         mlen;
2148       {
2149         char buf[size] GNUNET_ALIGN;
2150         struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2151         struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2152         struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2153         struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2154         msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2155         msg->size = htons (size);
2156         tun->flags = htons (0);
2157         tun->proto = htons (ETH_P_IPV6);
2158         GNUNET_TUN_initialize_ipv6_header (ipv6,
2159                                            IPPROTO_UDP,
2160                                            sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2161                                            &ts->destination_ip.v6,
2162                                            &ts->source_ip.v6);
2163         if (0 == ntohs (reply->source_port))
2164           udp->source_port = htons (ts->destination_port);
2165         else
2166           udp->source_port = reply->source_port;
2167         if (0 == ntohs (reply->destination_port))
2168           udp->destination_port = htons (ts->source_port);
2169         else
2170           udp->destination_port = reply->destination_port;
2171         udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2172         GNUNET_TUN_calculate_udp6_checksum (ipv6,
2173                                             udp,
2174                                             &reply[1], mlen);
2175         memcpy (&udp[1],
2176                 &reply[1],
2177                 mlen);
2178         (void) GNUNET_HELPER_send (helper_handle,
2179                                    msg,
2180                                    GNUNET_YES,
2181                                    NULL, NULL);
2182       }
2183     }
2184     break;
2185   default:
2186     GNUNET_assert (0);
2187   }
2188   GNUNET_CONTAINER_heap_update_cost (tunnel_heap, 
2189                                      ts->heap_node,
2190                                      GNUNET_TIME_absolute_get ().abs_value);
2191   return GNUNET_OK;
2192 }
2193
2194
2195 /**
2196  * We got a TCP packet back from the MESH tunnel.  Pass it on to the
2197  * local virtual interface via the helper.
2198  *
2199  * @param cls closure, NULL
2200  * @param tunnel connection to the other end
2201  * @param tunnel_ctx pointer to our 'struct TunnelState *'
2202  * @param sender who sent the message
2203  * @param message the actual message
2204  * @param atsi performance data for the connection
2205  * @return GNUNET_OK to keep the connection open,
2206  *         GNUNET_SYSERR to close it (signal serious error)
2207  */ 
2208 static int
2209 receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
2210                   void **tunnel_ctx,
2211                   const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
2212                   const struct GNUNET_MessageHeader *message,
2213                   const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
2214 {
2215   struct TunnelState *ts = *tunnel_ctx;
2216   const struct GNUNET_EXIT_TcpDataMessage *data;
2217   size_t mlen;
2218
2219   GNUNET_STATISTICS_update (stats,
2220                             gettext_noop ("# TCP packets received from mesh"),
2221                             1, GNUNET_NO);
2222   mlen = ntohs (message->size);
2223   if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2224   {
2225     GNUNET_break_op (0);
2226     return GNUNET_SYSERR;
2227   }
2228   if (NULL == ts->heap_node)
2229   {
2230     GNUNET_break_op (0);
2231     return GNUNET_SYSERR;
2232   }
2233   data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2234   mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2235   {
2236     char sbuf[INET6_ADDRSTRLEN];
2237     char dbuf[INET6_ADDRSTRLEN];
2238     
2239     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2240                 "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n",
2241                 (unsigned int) mlen,
2242                 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2243                 ts->destination_port,
2244                 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2245                 ts->source_port);
2246   }
2247   if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2248   {
2249     GNUNET_break_op (0);
2250     return GNUNET_SYSERR;
2251   }
2252   switch (ts->af)
2253   {
2254   case AF_INET:
2255     {
2256       size_t size = sizeof (struct GNUNET_TUN_IPv4Header) 
2257         + sizeof (struct GNUNET_TUN_TcpHeader) 
2258         + sizeof (struct GNUNET_MessageHeader) +
2259         sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2260         mlen;
2261       {
2262         char buf[size] GNUNET_ALIGN;
2263         struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2264         struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2265         struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2266         struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2267         msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2268         msg->size = htons (size);
2269         tun->flags = htons (0);
2270         tun->proto = htons (ETH_P_IPV4);
2271         GNUNET_TUN_initialize_ipv4_header (ipv4,
2272                                            IPPROTO_TCP,
2273                                            sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2274                                            &ts->destination_ip.v4,
2275                                            &ts->source_ip.v4);
2276         *tcp = data->tcp_header;
2277         tcp->source_port = htons (ts->destination_port);
2278         tcp->destination_port = htons (ts->source_port);
2279         GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2280                                             tcp,
2281                                             &data[1],
2282                                             mlen);
2283         memcpy (&tcp[1],
2284                 &data[1],
2285                 mlen);
2286         (void) GNUNET_HELPER_send (helper_handle,
2287                                    msg,
2288                                    GNUNET_YES,
2289                                    NULL, NULL);
2290       }
2291     }
2292     break;
2293   case AF_INET6:
2294     {
2295       size_t size = sizeof (struct GNUNET_TUN_IPv6Header) 
2296         + sizeof (struct GNUNET_TUN_TcpHeader) 
2297         + sizeof (struct GNUNET_MessageHeader) +
2298         sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2299         mlen;
2300       {
2301         char buf[size] GNUNET_ALIGN;
2302         struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2303         struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2304         struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2305         struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2306         msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2307         msg->size = htons (size);
2308         tun->flags = htons (0);
2309         tun->proto = htons (ETH_P_IPV6);
2310         GNUNET_TUN_initialize_ipv6_header (ipv6,
2311                                            IPPROTO_TCP,
2312                                            sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2313                                            &ts->destination_ip.v6,
2314                                            &ts->source_ip.v6);
2315         *tcp = data->tcp_header;
2316         tcp->source_port = htons (ts->destination_port);
2317         tcp->destination_port = htons (ts->source_port);
2318         GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2319                                             tcp,
2320                                             &data[1],
2321                                             mlen);
2322         memcpy (&tcp[1],
2323                 &data[1],
2324                 mlen);
2325         (void) GNUNET_HELPER_send (helper_handle,
2326                                    msg,
2327                                    GNUNET_YES,
2328                                    NULL, NULL);
2329       }
2330     }
2331     break;
2332   }
2333   GNUNET_CONTAINER_heap_update_cost (tunnel_heap, 
2334                                      ts->heap_node,
2335                                      GNUNET_TIME_absolute_get ().abs_value);
2336   return GNUNET_OK;
2337 }
2338
2339
2340 /**
2341  * Allocate an IPv4 address from the range of the tunnel
2342  * for a new redirection.
2343  *
2344  * @param v4 where to store the address
2345  * @return GNUNET_OK on success,
2346  *         GNUNET_SYSERR on error
2347  */
2348 static int
2349 allocate_v4_address (struct in_addr *v4)
2350 {
2351   const char *ipv4addr = vpn_argv[4];
2352   const char *ipv4mask = vpn_argv[5];
2353   struct in_addr addr;
2354   struct in_addr mask;
2355   struct in_addr rnd;
2356   struct GNUNET_HashCode key;
2357   unsigned int tries;
2358
2359   GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2360   GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));           
2361   /* Given 192.168.0.1/255.255.0.0, we want a mask 
2362      of '192.168.255.255', thus:  */
2363   mask.s_addr = addr.s_addr | ~mask.s_addr;  
2364   tries = 0;
2365   do
2366     {
2367       tries++;
2368       if (tries > 16)
2369       {
2370         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2371                     _("Failed to find unallocated IPv4 address in VPN's range\n"));
2372         return GNUNET_SYSERR;
2373       }
2374       /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2375       rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 
2376                                              UINT32_MAX);       
2377       v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;          
2378       get_destination_key_from_ip (AF_INET,
2379                                    v4,
2380                                    &key);
2381     }
2382   while ( (GNUNET_YES ==
2383            GNUNET_CONTAINER_multihashmap_contains (destination_map,
2384                                                    &key)) ||
2385           (v4->s_addr == addr.s_addr) ||
2386           (v4->s_addr == mask.s_addr) );
2387   return GNUNET_OK;
2388 }
2389
2390
2391 /**
2392  * Allocate an IPv6 address from the range of the tunnel
2393  * for a new redirection.
2394  *
2395  * @param v6 where to store the address
2396  * @return GNUNET_OK on success,
2397  *         GNUNET_SYSERR on error
2398  */
2399 static int
2400 allocate_v6_address (struct in6_addr *v6)
2401 {
2402   const char *ipv6addr = vpn_argv[2];
2403   struct in6_addr addr;
2404   struct in6_addr mask;
2405   struct in6_addr rnd;
2406   int i;
2407   struct GNUNET_HashCode key;
2408   unsigned int tries;
2409
2410   GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2411   GNUNET_assert (ipv6prefix < 128);
2412   /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2413      thus: */
2414   mask = addr;
2415   for (i=127;i>=ipv6prefix;i--)
2416     mask.s6_addr[i / 8] |= (1 << (i % 8));
2417   
2418   /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2419   tries = 0;
2420   do
2421     {
2422       tries++;
2423       if (tries > 16)
2424         {
2425           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2426                       _("Failed to find unallocated IPv6 address in VPN's range\n"));
2427           return GNUNET_SYSERR;
2428
2429         }
2430       for (i=0;i<16;i++)
2431         {
2432           rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 
2433                                                                      256);
2434           v6->s6_addr[i]
2435             = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2436         }
2437       get_destination_key_from_ip (AF_INET6,
2438                                    v6,
2439                                    &key);
2440     }
2441   while ( (GNUNET_YES ==
2442            GNUNET_CONTAINER_multihashmap_contains (destination_map,
2443                                                    &key)) ||
2444           (0 == memcmp (v6,
2445                         &addr,
2446                         sizeof (struct in6_addr))) ||
2447           (0 == memcmp (v6,
2448                         &mask,
2449                         sizeof (struct in6_addr))) );
2450   return GNUNET_OK;
2451 }
2452
2453
2454 /**
2455  * Free resources occupied by a destination entry.
2456  *
2457  * @param de entry to free
2458  */
2459 static void
2460 free_destination_entry (struct DestinationEntry *de)
2461 {
2462   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2463               "Cleaning up destination entry\n");
2464   GNUNET_STATISTICS_update (stats,
2465                             gettext_noop ("# Active destinations"),
2466                             -1, GNUNET_NO);
2467   if (NULL != de->ts)
2468   {
2469     free_tunnel_state (de->ts);
2470     GNUNET_assert (NULL == de->ts);
2471   }
2472   if (NULL != de->heap_node)
2473   {
2474     GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2475     de->heap_node = NULL;  
2476     GNUNET_assert (GNUNET_YES ==
2477                    GNUNET_CONTAINER_multihashmap_remove (destination_map,
2478                                                          &de->key,
2479                                                          de));
2480   }
2481   GNUNET_free (de);
2482 }
2483
2484
2485 /**
2486  * We have too many active destinations.  Clean up the oldest destination.
2487  *
2488  * @param except destination that must NOT be cleaned up, even if it is the oldest
2489  */
2490 static void 
2491 expire_destination (struct DestinationEntry *except)
2492 {
2493   struct DestinationEntry *de;
2494
2495   de = GNUNET_CONTAINER_heap_peek (destination_heap);
2496   GNUNET_assert (NULL != de);
2497   if (except == de)
2498     return; /* can't do this */
2499   free_destination_entry (de);
2500 }
2501
2502
2503 /**
2504  * Allocate an IP address for the response.  
2505  *
2506  * @param result_af desired address family; set to the actual
2507  *        address family; can initially be AF_UNSPEC if there
2508  *        is no preference; will be set to AF_UNSPEC if the
2509  *        allocation failed
2510  * @param addr set to either v4 or v6 depending on which 
2511  *         storage location was used; set to NULL if allocation failed
2512  * @param v4 storage space for an IPv4 address
2513  * @param v6 storage space for an IPv6 address
2514  * @return GNUNET_OK normally, GNUNET_SYSERR if '*result_af' was
2515  *         an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2516  */
2517 static int
2518 allocate_response_ip (int *result_af,
2519                       void **addr,
2520                       struct in_addr *v4,
2521                       struct in6_addr *v6)
2522 {
2523   *addr = NULL;
2524   switch (*result_af)
2525   {
2526   case AF_INET:
2527     if (GNUNET_OK !=
2528         allocate_v4_address (v4))
2529       *result_af = AF_UNSPEC;
2530     else
2531       *addr = v4;
2532     break;
2533   case AF_INET6:
2534     if (GNUNET_OK !=
2535         allocate_v6_address (v6))
2536       *result_af = AF_UNSPEC;
2537     else
2538       *addr = v6;
2539     break;
2540   case AF_UNSPEC:
2541     if (GNUNET_OK ==
2542         allocate_v4_address (v4))
2543     {
2544       *addr = v4;
2545       *result_af = AF_INET;
2546     }
2547     else if (GNUNET_OK ==
2548         allocate_v6_address (v6))
2549     {
2550       *addr = v6;
2551       *result_af = AF_INET6;
2552     }
2553     break;
2554   default:
2555     GNUNET_break (0);
2556     return GNUNET_SYSERR;
2557   }
2558   return GNUNET_OK;
2559 }                     
2560
2561
2562 /**
2563  * A client asks us to setup a redirection via some exit
2564  * node to a particular IP.  Setup the redirection and
2565  * give the client the allocated IP.
2566  *
2567  * @param cls unused
2568  * @param client requesting client
2569  * @param message redirection request (a 'struct RedirectToIpRequestMessage')
2570  */
2571 static void
2572 service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2573                         const struct GNUNET_MessageHeader *message)
2574 {
2575   size_t mlen;
2576   size_t alen;
2577   const struct RedirectToIpRequestMessage *msg;
2578   int addr_af;
2579   int result_af;
2580   struct in_addr v4;
2581   struct in6_addr v6;
2582   void *addr;
2583   struct DestinationEntry *de;
2584   struct GNUNET_HashCode key;
2585   struct TunnelState *ts;
2586   
2587   /* validate and parse request */
2588   mlen = ntohs (message->size);
2589   if (mlen < sizeof (struct RedirectToIpRequestMessage))
2590   {
2591     GNUNET_break (0);
2592     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2593     return;
2594   }
2595   alen = mlen - sizeof (struct RedirectToIpRequestMessage);
2596   msg = (const struct RedirectToIpRequestMessage *) message;
2597   addr_af = (int) htonl (msg->addr_af);
2598   switch (addr_af)
2599   {
2600   case AF_INET:
2601     if (alen != sizeof (struct in_addr))
2602     {
2603       GNUNET_break (0);
2604       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2605       return;      
2606     }
2607     break;
2608   case AF_INET6:
2609     if (alen != sizeof (struct in6_addr))
2610     {
2611       GNUNET_break (0);
2612       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2613       return;      
2614     }
2615     break;
2616   default:
2617     GNUNET_break (0);
2618     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2619     return;      
2620   }
2621
2622   /* allocate response IP */
2623   result_af = (int) htonl (msg->result_af);
2624   if (GNUNET_OK != allocate_response_ip (&result_af,
2625                                          &addr,
2626                                          &v4, &v6))
2627   {
2628     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2629     return;      
2630   }
2631   if ( (result_af == AF_UNSPEC) ||
2632        (GNUNET_NO == ntohl (msg->nac)) )
2633   {
2634     /* send reply "instantly" */
2635     send_client_reply (client,
2636                        msg->request_id,
2637                        result_af,
2638                        addr);
2639   }
2640   if (result_af == AF_UNSPEC)
2641   {
2642     /* failure, we're done */
2643     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2644     return;
2645   }
2646
2647   {
2648     char sbuf[INET6_ADDRSTRLEN];
2649     char dbuf[INET6_ADDRSTRLEN];
2650     
2651     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2652                 "Allocated address %s for redirection via exit to %s\n",
2653                 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2654                 inet_ntop (addr_af,
2655                            &msg[1], dbuf, sizeof (dbuf)));
2656   }
2657   
2658   /* setup destination record */
2659   de = GNUNET_malloc (sizeof (struct DestinationEntry));
2660   de->is_service = GNUNET_NO;
2661   de->details.exit_destination.af = addr_af;
2662   memcpy (&de->details.exit_destination.ip,
2663           &msg[1],
2664           alen);
2665   get_destination_key_from_ip (result_af,
2666                                addr,
2667                                &key);
2668   de->key = key;
2669   GNUNET_assert (GNUNET_OK ==
2670                  GNUNET_CONTAINER_multihashmap_put (destination_map,
2671                                                     &key,
2672                                                     de,
2673                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2674   de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2675                                                 de,
2676                                                 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2677   GNUNET_STATISTICS_update (stats,
2678                             gettext_noop ("# Active destinations"),
2679                             1, GNUNET_NO);
2680   while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2681     expire_destination (de);
2682   
2683   /* setup tunnel to destination */
2684   ts = create_tunnel_to_destination (de, 
2685                                      (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2686                                      result_af,
2687                                      msg->request_id);
2688   switch (result_af)
2689   {
2690   case AF_INET:
2691     ts->destination_ip.v4 = v4;
2692     break;
2693   case AF_INET6:
2694     ts->destination_ip.v6 = v6;
2695     break;
2696   default:
2697     GNUNET_assert (0);
2698   }
2699   /* we're done */
2700   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2701 }
2702
2703
2704 /**
2705  * A client asks us to setup a redirection to a particular peer
2706  * offering a service.  Setup the redirection and give the client the
2707  * allocated IP.
2708  *
2709  * @param cls unused
2710  * @param client requesting client
2711  * @param message redirection request (a 'struct RedirectToPeerRequestMessage')
2712  */
2713 static void
2714 service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
2715                              const struct GNUNET_MessageHeader *message)
2716 {
2717   const struct RedirectToServiceRequestMessage *msg;
2718   int result_af;
2719   struct in_addr v4;
2720   struct in6_addr v6;
2721   void *addr;
2722   struct DestinationEntry *de;
2723   struct GNUNET_HashCode key;
2724   struct TunnelState *ts;
2725   
2726   /*  parse request */
2727   msg = (const struct RedirectToServiceRequestMessage *) message;
2728
2729   /* allocate response IP */
2730   result_af = (int) htonl (msg->result_af);
2731   if (GNUNET_OK != allocate_response_ip (&result_af,
2732                                          &addr,
2733                                          &v4, &v6))
2734   {
2735     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2736     return;      
2737   }
2738   if ( (result_af == AF_UNSPEC) ||
2739        (GNUNET_NO == ntohl (msg->nac)) )
2740   {
2741     /* send reply "instantly" */
2742     send_client_reply (client,
2743                        msg->request_id,
2744                        result_af,
2745                        addr);
2746   }
2747   if (result_af == AF_UNSPEC)
2748   {
2749     /* failure, we're done */
2750     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2751                 _("Failed to allocate IP address for new destination\n"));
2752     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2753     return;
2754   }
2755
2756   {
2757     char sbuf[INET6_ADDRSTRLEN];
2758     
2759     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2760                 "Allocated address %s for redirection to service %s on peer %s\n",
2761                 inet_ntop (result_af, addr, sbuf, sizeof (sbuf)),
2762                 GNUNET_h2s (&msg->service_descriptor),
2763                 GNUNET_i2s (&msg->target));
2764   }
2765   
2766   /* setup destination record */
2767   de = GNUNET_malloc (sizeof (struct DestinationEntry));
2768   de->is_service = GNUNET_YES;
2769   de->details.service_destination.service_descriptor = msg->service_descriptor;
2770   de->details.service_destination.target = msg->target;
2771   get_destination_key_from_ip (result_af,
2772                                addr,
2773                                &key);
2774   de->key = key;
2775   GNUNET_assert (GNUNET_OK ==
2776                  GNUNET_CONTAINER_multihashmap_put (destination_map,
2777                                                     &key,
2778                                                     de,
2779                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2780   de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2781                                                 de,
2782                                                 GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value);
2783   while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings)
2784     expire_destination (de);
2785   ts = create_tunnel_to_destination (de,
2786                                      (GNUNET_NO == ntohl (msg->nac)) ? NULL : client,
2787                                      result_af,
2788                                      msg->request_id);
2789   switch (result_af)
2790   {
2791   case AF_INET:
2792     ts->destination_ip.v4 = v4;
2793     break;
2794   case AF_INET6:
2795     ts->destination_ip.v6 = v6;
2796     break;
2797   default:
2798     GNUNET_assert (0);
2799   }
2800   /* we're done */
2801   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2802 }
2803
2804
2805
2806 /**
2807  * Function called for inbound tunnels.  As we don't offer
2808  * any mesh services, this function should never be called.
2809  *
2810  * @param cls closure
2811  * @param tunnel new handle to the tunnel
2812  * @param initiator peer that started the tunnel
2813  * @param atsi performance information for the tunnel
2814  * @return initial tunnel context for the tunnel
2815  *         (can be NULL -- that's not an error)
2816  */ 
2817 static void *
2818 inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
2819                    const struct GNUNET_PeerIdentity *initiator,
2820                    const struct GNUNET_ATS_Information *atsi)
2821 {
2822   /* How can and why should anyone open an inbound tunnel to vpn? */
2823   GNUNET_break (0);
2824   return NULL;
2825 }
2826
2827
2828 /**
2829  * Function called whenever an inbound tunnel is destroyed.  Should clean up
2830  * any associated state.
2831  *
2832  * @param cls closure (set from GNUNET_MESH_connect)
2833  * @param tunnel connection to the other end (henceforth invalid)
2834  * @param tunnel_ctx place where local state associated
2835  *                   with the tunnel is stored (our 'struct TunnelState')
2836  */ 
2837 static void
2838 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx)
2839 {
2840   /* we don't have inbound tunnels, so this function should never be called */
2841   GNUNET_break (0);
2842 }
2843
2844
2845 /**
2846  * Free memory occupied by an entry in the destination map.
2847  *
2848  * @param cls unused
2849  * @param key unused
2850  * @param value a 'struct DestinationEntry *'
2851  * @return GNUNET_OK (continue to iterate)
2852  */
2853 static int
2854 cleanup_destination (void *cls,
2855                      const struct GNUNET_HashCode *key,
2856                      void *value)
2857 {
2858   struct DestinationEntry *de = value;
2859
2860   free_destination_entry (de);
2861   return GNUNET_OK;
2862 }
2863
2864
2865 /**
2866  * Free memory occupied by an entry in the tunnel map.
2867  *
2868  * @param cls unused
2869  * @param key unused
2870  * @param value a 'struct TunnelState *'
2871  * @return GNUNET_OK (continue to iterate)
2872  */
2873 static int
2874 cleanup_tunnel (void *cls,
2875                 const struct GNUNET_HashCode *key,
2876                 void *value)
2877 {
2878   struct TunnelState *ts = value;
2879
2880   free_tunnel_state (ts);
2881   return GNUNET_OK;
2882 }
2883
2884
2885 /**
2886  * Function scheduled as very last function, cleans up after us
2887  *
2888  * @param cls unused
2889  * @param tc unused
2890  */
2891 static void
2892 cleanup (void *cls GNUNET_UNUSED,
2893          const struct GNUNET_SCHEDULER_TaskContext *tc)
2894 {
2895   unsigned int i;
2896
2897   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2898               "VPN is shutting down\n");
2899   if (NULL != destination_map)
2900   {  
2901     GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2902                                            &cleanup_destination,
2903                                            NULL);
2904     GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2905     destination_map = NULL;
2906   }
2907   if (NULL != destination_heap)
2908   {
2909     GNUNET_CONTAINER_heap_destroy (destination_heap);
2910     destination_heap = NULL;
2911   }
2912   if (NULL != tunnel_map)
2913   {  
2914     GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
2915                                            &cleanup_tunnel,
2916                                            NULL);
2917     GNUNET_CONTAINER_multihashmap_destroy (tunnel_map);
2918     tunnel_map = NULL;
2919   }
2920   if (NULL != tunnel_heap)
2921   {
2922     GNUNET_CONTAINER_heap_destroy (tunnel_heap);
2923     tunnel_heap = NULL;
2924   }
2925   if (NULL != mesh_handle)
2926   {
2927     GNUNET_MESH_disconnect (mesh_handle);
2928     mesh_handle = NULL;
2929   }
2930   if (NULL != helper_handle)
2931     {
2932     GNUNET_HELPER_stop (helper_handle);
2933     helper_handle = NULL;
2934   }
2935   if (NULL != nc)
2936   {
2937     GNUNET_SERVER_notification_context_destroy (nc);
2938     nc = NULL;
2939   }
2940   if (stats != NULL)
2941   {
2942     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2943     stats = NULL;
2944   }
2945   for (i=0;i<5;i++)
2946     GNUNET_free_non_null (vpn_argv[i]);
2947 }
2948
2949
2950 /**
2951  * A client disconnected, clean up all references to it.
2952  *
2953  * @param cls the client that disconnected
2954  * @param key unused
2955  * @param value a 'struct TunnelState *'
2956  * @return GNUNET_OK (continue to iterate)
2957  */
2958 static int
2959 cleanup_tunnel_client (void *cls,
2960                        const struct GNUNET_HashCode *key,
2961                        void *value)
2962 {
2963   struct GNUNET_SERVER_Client *client = cls;
2964   struct TunnelState *ts = value;
2965
2966   if (client == ts->client)
2967   {
2968     GNUNET_SERVER_client_drop (ts->client);
2969     ts->client = NULL;
2970   }
2971   return GNUNET_OK;
2972 }
2973
2974
2975 /**
2976  * A client disconnected, clean up all references to it.
2977  *
2978  * @param cls the client that disconnected
2979  * @param key unused
2980  * @param value a 'struct DestinationEntry *'
2981  * @return GNUNET_OK (continue to iterate)
2982  */
2983 static int
2984 cleanup_destination_client (void *cls,
2985                             const struct GNUNET_HashCode *key,
2986                             void *value)
2987 {
2988   struct GNUNET_SERVER_Client *client = cls;
2989   struct DestinationEntry *de = value;
2990   struct TunnelState *ts;
2991
2992   if (NULL == (ts = de->ts))
2993     return GNUNET_OK;
2994   if (client == ts->client)
2995   {
2996     GNUNET_SERVER_client_drop (ts->client);
2997     ts->client = NULL;
2998   }
2999   return GNUNET_OK;
3000 }
3001
3002   
3003 /**
3004  * A client has disconnected from us.  If we are currently building
3005  * a tunnel for it, cancel the operation.
3006  *
3007  * @param cls unused
3008  * @param client handle to the client that disconnected
3009  */
3010 static void
3011 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
3012 {
3013   if (NULL != tunnel_map)
3014     GNUNET_CONTAINER_multihashmap_iterate (tunnel_map,
3015                                            &cleanup_tunnel_client,
3016                                            client);
3017   if (NULL != destination_map)
3018     GNUNET_CONTAINER_multihashmap_iterate (destination_map,
3019                                            &cleanup_destination_client,
3020                                            client);
3021 }
3022
3023
3024 /**
3025  * Main function that will be run by the scheduler.
3026  *
3027  * @param cls closure
3028  * @param server the initialized server
3029  * @param cfg_ configuration
3030  */
3031 static void
3032 run (void *cls,
3033      struct GNUNET_SERVER_Handle *server,
3034      const struct GNUNET_CONFIGURATION_Handle *cfg_)
3035 {
3036   static const struct GNUNET_SERVER_MessageHandler service_handlers[] = {
3037     /* callback, cls, type, size */
3038     { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0},
3039     { &service_redirect_to_service, NULL, 
3040      GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE, 
3041      sizeof (struct RedirectToServiceRequestMessage) },
3042     {NULL, NULL, 0, 0}
3043   };
3044   static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
3045     { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
3046     { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
3047     { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
3048     {NULL, 0, 0}
3049   };
3050   static const GNUNET_MESH_ApplicationType types[] = {
3051     GNUNET_APPLICATION_TYPE_END
3052   };
3053   char *ifname;
3054   char *ipv6addr;
3055   char *ipv6prefix_s;
3056   char *ipv4addr;
3057   char *ipv4mask;
3058   struct in_addr v4;
3059   struct in6_addr v6;
3060   char *binary;
3061
3062   binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
3063
3064   if (GNUNET_YES !=
3065       GNUNET_OS_check_helper_binary (binary))
3066   {
3067     fprintf (stderr,
3068              "`%s' is not SUID, refusing to run.\n",
3069              "gnunet-helper-vpn");
3070     GNUNET_free (binary);
3071     global_ret = 1;
3072     return;
3073   }
3074   GNUNET_free (binary);
3075   cfg = cfg_;
3076   stats = GNUNET_STATISTICS_create ("vpn", cfg);
3077   if (GNUNET_OK !=
3078       GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING",
3079                                              &max_destination_mappings))
3080     max_destination_mappings = 200;
3081   if (GNUNET_OK !=
3082       GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS",
3083                                              &max_tunnel_mappings))
3084     max_tunnel_mappings = 200;
3085
3086   destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2, GNUNET_NO);
3087   destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3088   tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2, GNUNET_NO);
3089   tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3090
3091
3092   vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
3093   if (GNUNET_SYSERR ==
3094       GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname))
3095   {
3096     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3097                 "No entry 'IFNAME' in configuration!\n");
3098     GNUNET_SCHEDULER_shutdown ();
3099     return;
3100   }
3101   vpn_argv[1] = ifname;
3102   if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
3103   {
3104     if ( (GNUNET_SYSERR ==
3105           GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR",
3106                                                  &ipv6addr) ||
3107           (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
3108     {
3109       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3110                   "No valid entry 'IPV6ADDR' in configuration!\n");
3111       GNUNET_SCHEDULER_shutdown ();
3112       return;
3113     }
3114     vpn_argv[2] = ipv6addr;
3115     if (GNUNET_SYSERR ==
3116         GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX",
3117                                                &ipv6prefix_s))
3118     {
3119       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3120                   "No entry 'IPV6PREFIX' in configuration!\n");
3121       GNUNET_SCHEDULER_shutdown ();
3122       return;
3123     }
3124     vpn_argv[3] = ipv6prefix_s;
3125     if ( (GNUNET_OK !=
3126           GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
3127                                                  "IPV6PREFIX",
3128                                                  &ipv6prefix)) ||
3129          (ipv6prefix >= 127) )
3130     {
3131       GNUNET_SCHEDULER_shutdown ();
3132       return;
3133     }
3134   }
3135   else
3136   {
3137     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3138                 _("IPv6 support disabled as this system does not support IPv6\n"));
3139     vpn_argv[2] = GNUNET_strdup ("-");
3140     vpn_argv[3] = GNUNET_strdup ("-");
3141   }
3142   if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET))
3143   {
3144     if ( (GNUNET_SYSERR ==
3145           GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR",
3146                                                  &ipv4addr) ||
3147           (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
3148     {
3149       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3150                   "No valid entry for 'IPV4ADDR' in configuration!\n");
3151       GNUNET_SCHEDULER_shutdown ();
3152       return;
3153     }
3154     vpn_argv[4] = ipv4addr;
3155     if ( (GNUNET_SYSERR ==
3156           GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK",
3157                                                  &ipv4mask) ||
3158           (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
3159     {
3160       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3161                   "No valid entry 'IPV4MASK' in configuration!\n");
3162       GNUNET_SCHEDULER_shutdown ();
3163       return;
3164     }
3165     vpn_argv[5] = ipv4mask;
3166   }
3167   else
3168   {
3169     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3170                 _("IPv4 support disabled as this system does not support IPv4\n"));
3171     vpn_argv[4] = GNUNET_strdup ("-");
3172     vpn_argv[5] = GNUNET_strdup ("-");
3173   }
3174   vpn_argv[6] = NULL;
3175
3176   mesh_handle =
3177     GNUNET_MESH_connect (cfg_, NULL, 
3178                          &inbound_tunnel_cb, 
3179                          &tunnel_cleaner, 
3180                          mesh_handlers,
3181                          types);
3182   helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3183                                        "gnunet-helper-vpn", vpn_argv,
3184                                        &message_token, NULL, NULL);
3185   nc = GNUNET_SERVER_notification_context_create (server, 1);
3186   GNUNET_SERVER_add_handlers (server, service_handlers);
3187   GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
3188   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
3189 }
3190
3191
3192 /**
3193  * The main function of the VPN service.
3194  *
3195  * @param argc number of arguments from the command line
3196  * @param argv command line arguments
3197  * @return 0 ok, 1 on error
3198  */
3199 int
3200 main (int argc, char *const *argv)
3201 {
3202   return (GNUNET_OK ==
3203           GNUNET_SERVICE_run (argc, argv, "vpn", 
3204                               GNUNET_SERVICE_OPTION_NONE,
3205                               &run, NULL)) ? global_ret : 1;
3206 }
3207
3208 /* end of gnunet-service-vpn.c */