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