curly wars / auto-indentation
[oweals/gnunet.git] / src / vpn / gnunet-daemon-exit.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010 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-daemon-exit.c
23  * @brief
24  * @author Philipp Toelke
25  */
26 #include <platform.h>
27 #include <gnunet_common.h>
28 #include <gnunet_program_lib.h>
29 #include <gnunet_protocols.h>
30 #include <gnunet_applications.h>
31 #include <gnunet_mesh_service.h>
32 #include <gnunet_constants.h>
33 #include <string.h>
34
35 #include "gnunet-vpn-packet.h"
36 #include "gnunet-helper-vpn-api.h"
37 #include "gnunet-vpn-checksum.h"
38
39 GNUNET_SCHEDULER_TaskIdentifier shs_task;
40
41 /**
42  * The handle to the configuration used throughout the process
43  */
44 static const struct GNUNET_CONFIGURATION_Handle *cfg;
45
46 /**
47  * The handle to the helper
48  */
49 struct GNUNET_VPN_HELPER_Handle *helper_handle;
50
51 /**
52  * Final status code.
53  */
54 static int ret;
55
56 /**
57  * The handle to mesh
58  */
59 static struct GNUNET_MESH_Handle *mesh_handle;
60
61 /**
62  * This hashmaps contains the mapping from peer, service-descriptor,
63  * source-port and destination-port to a struct redirect_state
64  */
65 static struct GNUNET_CONTAINER_MultiHashMap *udp_connections;
66 static struct GNUNET_CONTAINER_Heap *udp_connections_heap;
67 static struct GNUNET_CONTAINER_MultiHashMap *tcp_connections;
68 static struct GNUNET_CONTAINER_Heap *tcp_connections_heap;
69
70 /**
71  * If there are at least this many udp-Connections, old ones will be removed
72  */
73 static long long unsigned int max_udp_connections = 200;
74
75 /**
76  * If there are at least this many tcp-Connections, old ones will be removed
77  */
78 static long long unsigned int max_tcp_connections = 200;
79
80 struct remote_addr
81 {
82   char addrlen;
83   unsigned char addr[16];
84   char proto;
85 };
86
87 /**
88  * This struct is saved into the services-hashmap
89  */
90 struct redirect_service
91 {
92   /**
93    * One of 4 or 6
94    */
95   unsigned int version;
96   uint16_t my_port;
97   uint16_t remote_port;
98
99   union
100   {
101     struct
102     {
103       char ip4address[4];
104     } v4;
105     struct
106     {
107       char ip6address[16];
108     } v6;
109   };
110 };
111
112 struct redirect_info
113 {
114     /**
115      * The source-address of this connection. When a packet to this address is
116      * received, this tunnel is used to forward it.  ipv4-addresses will be put
117      * here left-aligned */
118   char addr[16];
119     /**
120      * The source-port of this connection
121      */
122   uint16_t pt;
123 };
124
125 /**
126  * This struct is saved into {tcp,udp}_connections;
127  */
128 struct redirect_state
129 {
130   struct GNUNET_MESH_Tunnel *tunnel;
131   GNUNET_HashCode desc;
132   struct redirect_service *serv;
133   struct remote_addr remote;
134
135   struct GNUNET_CONTAINER_HeapNode *heap_node;
136   struct GNUNET_CONTAINER_MultiHashMap *hashmap;
137   GNUNET_HashCode hash;
138
139   enum
140   { SERVICE, REMOTE } type;
141
142   /**
143    * The source-address and -port of this connection
144    */
145   struct redirect_info redirect_info;
146 };
147
148 /**
149  * This hashmaps saves interesting things about the configured services
150  */
151 static struct GNUNET_CONTAINER_MultiHashMap *udp_services;
152 static struct GNUNET_CONTAINER_MultiHashMap *tcp_services;
153
154 struct tunnel_notify_queue
155 {
156   struct tunnel_notify_queue *next;
157   struct tunnel_notify_queue *prev;
158   void *cls;
159   size_t len;
160 };
161
162 struct tunnel_state
163 {
164   struct tunnel_notify_queue *head;
165   struct tunnel_notify_queue *tail;
166   struct GNUNET_MESH_TransmitHandle *th;
167 };
168
169 /**
170  * Function that frees everything from a hashmap
171  */
172 static int
173 free_iterate (void *cls __attribute__ ((unused)), const GNUNET_HashCode * hash
174               __attribute__ ((unused)), void *value)
175 {
176   GNUNET_free (value);
177   return GNUNET_YES;
178 }
179
180 /**
181  * Function scheduled as very last function, cleans up after us
182  */
183 static void
184 cleanup (void *cls
185          __attribute__ ((unused)),
186          const struct GNUNET_SCHEDULER_TaskContext *tskctx)
187 {
188   GNUNET_assert (0 != (tskctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN));
189
190   GNUNET_CONTAINER_multihashmap_iterate (udp_connections, free_iterate, NULL);
191
192   GNUNET_CONTAINER_multihashmap_iterate (tcp_connections, free_iterate, NULL);
193
194   if (mesh_handle != NULL)
195   {
196     GNUNET_MESH_disconnect (mesh_handle);
197     mesh_handle = NULL;
198   }
199 }
200
201 static void *
202 new_tunnel (void *cls
203             __attribute__ ((unused)), struct GNUNET_MESH_Tunnel *tunnel,
204             const struct GNUNET_PeerIdentity *initiator
205             __attribute__ ((unused)), const struct GNUNET_ATS_Information *ats
206             __attribute__ ((unused)))
207 {
208   struct tunnel_state *s = GNUNET_malloc (sizeof *s);
209
210   s->head = NULL;
211   s->tail = NULL;
212   s->th = NULL;
213   return s;
214 }
215
216 static void
217 clean_tunnel (void *cls
218               __attribute__ ((unused)), const struct GNUNET_MESH_Tunnel *tunnel,
219               void *tunnel_ctx)
220 {
221   GNUNET_free (tunnel_ctx);
222 }
223
224 static void
225 collect_connections (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
226 {
227   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
228     return;
229
230
231   struct GNUNET_CONTAINER_Heap *heap = cls;
232
233   struct redirect_state *state = GNUNET_CONTAINER_heap_remove_root (heap);
234
235   /* This is free()ed memory! */
236   state->heap_node = NULL;
237
238   /* FIXME! GNUNET_MESH_close_tunnel(state->tunnel); */
239
240   GNUNET_assert (GNUNET_OK ==
241                  GNUNET_CONTAINER_multihashmap_remove (state->hashmap,
242                                                        &state->hash, state));
243
244   GNUNET_free (state);
245 }
246
247 static void
248 hash_redirect_info (GNUNET_HashCode * hash, struct redirect_info *u_i,
249                     size_t addrlen)
250 {
251
252   /* the gnunet hashmap only uses the first sizeof(unsigned int) of the hash
253    *
254    * build the hash out of the last bytes of the address and the 2 bytes of
255    * the port
256    */
257   memcpy (hash, &u_i->pt, sizeof (u_i->pt));
258   memcpy (((unsigned char *) hash) + 2,
259           u_i->addr + (addrlen - (sizeof (unsigned int) - 2)),
260           (sizeof (unsigned int) - 2));
261   memset (((unsigned char *) hash) + sizeof (unsigned int), 0,
262           sizeof (GNUNET_HashCode) - sizeof (unsigned int));
263 }
264
265 /**
266  * cls is the pointer to a GNUNET_MessageHeader that is
267  * followed by the service-descriptor and the udp-packet that should be sent;
268  */
269 static size_t
270 send_udp_to_peer_notify_callback (void *cls, size_t size, void *buf)
271 {
272   struct GNUNET_MESH_Tunnel **tunnel = cls;
273
274   GNUNET_MESH_tunnel_set_data (*tunnel, NULL);
275   struct GNUNET_MessageHeader *hdr =
276       (struct GNUNET_MessageHeader *) (tunnel + 1);
277   GNUNET_assert (size >= ntohs (hdr->size));
278   memcpy (buf, hdr, ntohs (hdr->size));
279   size = ntohs (hdr->size);
280
281   struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (*tunnel);
282
283   if (NULL != s->head)
284   {
285     struct tunnel_notify_queue *element = s->head;
286
287     GNUNET_CONTAINER_DLL_remove (s->head, s->tail, element);
288
289     s->th =
290         GNUNET_MESH_notify_transmit_ready (*tunnel, GNUNET_NO, 42,
291                                            GNUNET_TIME_relative_divide
292                                            (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2),
293                                            (const struct GNUNET_PeerIdentity *)
294                                            NULL, element->len,
295                                            send_udp_to_peer_notify_callback,
296                                            element->cls);
297
298     /* save the handle */
299     GNUNET_free (element);
300   }
301
302   GNUNET_free (cls);
303
304   return size;
305 }
306
307 /**
308  * @brief Handles an UDP-Packet received from the helper.
309  *
310  * @param udp A pointer to the Packet
311  * @param dadr The IP-Destination-address
312  * @param addrlen The length of the address
313  */
314 static void
315 udp_from_helper (struct udp_pkt *udp, unsigned char *dadr, size_t addrlen)
316 {
317   struct redirect_info u_i;
318   struct GNUNET_MESH_Tunnel *tunnel;
319   uint32_t len;
320   struct GNUNET_MessageHeader *msg;
321
322   memset (&u_i, 0, sizeof (struct redirect_info));
323
324   memcpy (&u_i.addr, dadr, addrlen);
325
326   u_i.pt = udp->dpt;
327
328   /* get tunnel and service-descriptor from this */
329   GNUNET_HashCode hash;
330
331   hash_redirect_info (&hash, &u_i, addrlen);
332
333   struct redirect_state *state =
334       GNUNET_CONTAINER_multihashmap_get (udp_connections, &hash);
335
336   /* Mark this connection as freshly used */
337   GNUNET_CONTAINER_heap_update_cost (udp_connections_heap, state->heap_node,
338                                      GNUNET_TIME_absolute_get ().abs_value);
339
340   tunnel = state->tunnel;
341
342   if (state->type == SERVICE)
343   {
344     /* check if spt == serv.remote if yes: set spt = serv.myport ("nat") */
345     if (ntohs (udp->spt) == state->serv->remote_port)
346     {
347       udp->spt = htons (state->serv->my_port);
348     }
349     else
350     {
351       /* otherwise the answer came from a different port (tftp does this)
352        * add this new port to the list of all services, so that the packets
353        * coming back from the client to this new port will be routed correctly
354        */
355       struct redirect_service *serv =
356           GNUNET_malloc (sizeof (struct redirect_service));
357       memcpy (serv, state->serv, sizeof (struct redirect_service));
358       serv->my_port = ntohs (udp->spt);
359       serv->remote_port = ntohs (udp->spt);
360       uint16_t *desc = alloca (sizeof (GNUNET_HashCode) + 2);
361
362       memcpy ((GNUNET_HashCode *) (desc + 1), &state->desc,
363               sizeof (GNUNET_HashCode));
364       *desc = ntohs (udp->spt);
365       GNUNET_assert (GNUNET_OK ==
366                      GNUNET_CONTAINER_multihashmap_put (udp_services,
367                                                         (GNUNET_HashCode *)
368                                                         desc, serv,
369                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
370
371       state->serv = serv;
372     }
373   }
374
375   /* send udp-packet back */
376   len =
377       sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) +
378       ntohs (udp->len);
379   struct GNUNET_MESH_Tunnel **ctunnel =
380       GNUNET_malloc (sizeof (struct GNUNET_MESH_TUNNEL *) + len);
381   *ctunnel = tunnel;
382   msg = (struct GNUNET_MessageHeader *) (ctunnel + 1);
383   msg->size = htons (len);
384   msg->type =
385       htons (state->type ==
386              SERVICE ? GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK :
387              GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP_BACK);
388   GNUNET_HashCode *desc = (GNUNET_HashCode *) (msg + 1);
389
390   if (state->type == SERVICE)
391     memcpy (desc, &state->desc, sizeof (GNUNET_HashCode));
392   else
393     memcpy (desc, &state->remote, sizeof (struct remote_addr));
394   void *_udp = desc + 1;
395
396   memcpy (_udp, udp, ntohs (udp->len));
397
398   struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (tunnel);
399
400   if (NULL == s->th)
401   {
402     /* No notify is pending */
403     s->th =
404         GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO, 42,
405                                            GNUNET_TIME_relative_divide
406                                            (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2),
407                                            (const struct GNUNET_PeerIdentity *)
408                                            NULL, len,
409                                            send_udp_to_peer_notify_callback,
410                                            ctunnel);
411   }
412   else
413   {
414     struct tunnel_notify_queue *element =
415         GNUNET_malloc (sizeof (struct tunnel_notify_queue));
416     element->cls = ctunnel;
417     element->len = len;
418
419     GNUNET_CONTAINER_DLL_insert_tail (s->head, s->tail, element);
420   }
421 }
422
423 /**
424  * @brief Handles a TCP-Packet received from the helper.
425  *
426  * @param tcp A pointer to the Packet
427  * @param dadr The IP-Destination-address
428  * @param addrlen The length of the address
429  * @param pktlen the length of the packet, including its header
430  */
431 static void
432 tcp_from_helper (struct tcp_pkt *tcp, unsigned char *dadr, size_t addrlen,
433                  size_t pktlen)
434 {
435   struct redirect_info u_i;
436   struct GNUNET_MESH_Tunnel *tunnel;
437   uint32_t len;
438   struct GNUNET_MessageHeader *msg;
439
440   memset (&u_i, 0, sizeof (struct redirect_info));
441
442   memcpy (&u_i.addr, dadr, addrlen);
443   u_i.pt = tcp->dpt;
444
445   /* get tunnel and service-descriptor from this */
446   GNUNET_HashCode hash;
447
448   hash_redirect_info (&hash, &u_i, addrlen);
449
450   struct redirect_state *state =
451       GNUNET_CONTAINER_multihashmap_get (tcp_connections, &hash);
452
453   if (state == NULL)
454   {
455     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
456                 "No mapping for this connection; hash is %x\n",
457                 *((uint32_t *) & hash));
458     return;
459   }
460
461   /* Mark this connection as freshly used */
462   GNUNET_CONTAINER_heap_update_cost (tcp_connections_heap, state->heap_node,
463                                      GNUNET_TIME_absolute_get ().abs_value);
464
465   tunnel = state->tunnel;
466
467   if (state->type == SERVICE)
468   {
469     /* check if spt == serv.remote if yes: set spt = serv.myport ("nat") */
470     if (ntohs (tcp->spt) == state->serv->remote_port)
471     {
472       tcp->spt = htons (state->serv->my_port);
473     }
474     else
475     {
476       // This is an illegal packet.
477       return;
478     }
479   }
480
481   /* send tcp-packet back */
482   len =
483       sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + pktlen;
484   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "len: %d\n", pktlen);
485   struct GNUNET_MESH_Tunnel **ctunnel =
486       GNUNET_malloc (sizeof (struct GNUNET_MESH_TUNNEL *) + len);
487   *ctunnel = tunnel;
488   msg = (struct GNUNET_MessageHeader *) (ctunnel + 1);
489   msg->size = htons (len);
490   msg->type =
491       htons (state->type ==
492              SERVICE ? GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK :
493              GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP_BACK);
494   GNUNET_HashCode *desc = (GNUNET_HashCode *) (msg + 1);
495
496   if (state->type == SERVICE)
497     memcpy (desc, &state->desc, sizeof (GNUNET_HashCode));
498   else
499     memcpy (desc, &state->remote, sizeof (struct remote_addr));
500   void *_tcp = desc + 1;
501
502   memcpy (_tcp, tcp, pktlen);
503
504   struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (tunnel);
505
506   if (NULL == s->th)
507   {
508     /* No notify is pending */
509     s->th =
510         GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO, 42,
511                                            GNUNET_TIME_relative_divide
512                                            (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2),
513                                            (const struct GNUNET_PeerIdentity *)
514                                            NULL, len,
515                                            send_udp_to_peer_notify_callback,
516                                            ctunnel);
517   }
518   else
519   {
520     struct tunnel_notify_queue *element =
521         GNUNET_malloc (sizeof (struct tunnel_notify_queue));
522     element->cls = ctunnel;
523     element->len = len;
524
525     GNUNET_CONTAINER_DLL_insert_tail (s->head, s->tail, element);
526   }
527 }
528
529
530 /**
531  * Receive packets from the helper-process
532  */
533 static void
534 message_token (void *cls __attribute__ ((unused)), void *client
535                __attribute__ ((unused)),
536                const struct GNUNET_MessageHeader *message)
537 {
538   GNUNET_assert (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_HELPER);
539
540   struct tun_pkt *pkt_tun = (struct tun_pkt *) message;
541
542   /* ethertype is ipv6 */
543   if (ntohs (pkt_tun->tun.type) == 0x86dd)
544   {
545     struct ip6_pkt *pkt6 = (struct ip6_pkt *) pkt_tun;
546
547     if (IPPROTO_UDP == pkt6->ip6_hdr.nxthdr)
548       udp_from_helper (&((struct ip6_udp *) pkt6)->udp_hdr,
549                        (unsigned char *) &pkt6->ip6_hdr.dadr, 16);
550     else if (IPPROTO_TCP == pkt6->ip6_hdr.nxthdr)
551       tcp_from_helper (&((struct ip6_tcp *) pkt6)->tcp_hdr,
552                        (unsigned char *) &pkt6->ip6_hdr.dadr, 16,
553                        ntohs (pkt6->ip6_hdr.paylgth));
554   }
555   else if (ntohs (pkt_tun->tun.type) == 0x0800)
556   {
557     struct ip_pkt *pkt4 = (struct ip_pkt *) pkt_tun;
558     uint32_t tmp = pkt4->ip_hdr.dadr;
559
560     if (IPPROTO_UDP == pkt4->ip_hdr.proto)
561       udp_from_helper (&((struct ip_udp *) pkt4)->udp_hdr,
562                        (unsigned char *) &tmp, 4);
563     else if (IPPROTO_TCP == pkt4->ip_hdr.proto)
564     {
565       size_t pktlen = ntohs (pkt4->ip_hdr.tot_lngth);
566
567       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tot: %d\n", pktlen);
568       pktlen -= 4 * pkt4->ip_hdr.hdr_lngth;
569       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "-hdr: %d\n", pktlen);
570       tcp_from_helper (&((struct ip_tcp *) pkt4)->tcp_hdr,
571                        (unsigned char *) &tmp, 4, pktlen);
572     }
573   }
574   else
575   {
576     return;
577   }
578 }
579
580 /**
581  * Reads the configuration servicecfg and populates udp_services
582  *
583  * @param cls unused
584  * @param section name of section in config, equal to hostname
585  */
586 static void
587 read_service_conf (void *cls __attribute__ ((unused)), const char *section)
588 {
589   if ((strlen (section) < 8) ||
590       (0 != strcmp (".gnunet.", section + (strlen (section) - 8))))
591     return;
592
593   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing dns-name %d %s %s\n",
594               strlen (section), section, section + (strlen (section) - 8));
595
596   char *cpy;
597   char *redirect;
598   char *hostname;
599   char *hostport;
600   uint16_t *desc = alloca (sizeof (GNUNET_HashCode) + 2);
601
602   GNUNET_CRYPTO_hash (section, strlen (section) + 1,
603                       (GNUNET_HashCode *) (desc + 1));
604
605 #define TCP 2
606 #define UDP 1
607
608   int proto = UDP;
609
610   do
611   {
612     if (proto == UDP &&
613         (GNUNET_OK !=
614          GNUNET_CONFIGURATION_get_value_string (cfg, section, "UDP_REDIRECTS",
615                                                 &cpy)))
616       goto next;
617     else if (proto == TCP &&
618              (GNUNET_OK !=
619               GNUNET_CONFIGURATION_get_value_string (cfg, section,
620                                                      "TCP_REDIRECTS", &cpy)))
621       goto next;
622
623     for (redirect = strtok (cpy, " "); redirect != NULL;
624          redirect = strtok (NULL, " "))
625     {
626       if (NULL == (hostname = strstr (redirect, ":")))
627       {
628         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
629                     "Warning: option %s is not formatted correctly!\n",
630                     redirect);
631         continue;
632       }
633       hostname[0] = '\0';
634       hostname++;
635       if (NULL == (hostport = strstr (hostname, ":")))
636       {
637         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
638                     "Warning: option %s is not formatted correctly!\n",
639                     redirect);
640         continue;
641       }
642       hostport[0] = '\0';
643       hostport++;
644
645       int local_port = atoi (redirect);
646
647       if (!((local_port > 0) && (local_port < 65536)))
648         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
649                     "Warning: %s is not a correct port.", redirect);
650
651       *desc = local_port;
652
653       struct redirect_service *serv =
654           GNUNET_malloc (sizeof (struct redirect_service));
655       serv->my_port = local_port;
656
657       if (0 == strcmp ("localhost4", hostname))
658       {
659         serv->version = 4;
660
661         char *ip4addr;
662
663         GNUNET_assert (GNUNET_OK ==
664                        GNUNET_CONFIGURATION_get_value_string (cfg, "exit",
665                                                               "IPV4ADDR",
666                                                               &ip4addr));
667         GNUNET_assert (1 == inet_pton (AF_INET, ip4addr, serv->v4.ip4address));
668         GNUNET_free (ip4addr);
669       }
670       else if (0 == strcmp ("localhost6", hostname))
671       {
672         serv->version = 6;
673
674         char *ip6addr;
675
676         GNUNET_assert (GNUNET_OK ==
677                        GNUNET_CONFIGURATION_get_value_string (cfg, "exit",
678                                                               "IPV6ADDR",
679                                                               &ip6addr));
680         GNUNET_assert (1 == inet_pton (AF_INET6, ip6addr, serv->v6.ip6address));
681         GNUNET_free (ip6addr);
682       }
683       else
684       {
685         struct addrinfo *res;
686
687         int ret = getaddrinfo (hostname, NULL, NULL, &res);
688
689         if (ret != 0)
690         {
691           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No addresses found for %s!\n",
692                       hostname);
693           GNUNET_free (serv);
694           continue;
695         }
696         else
697         {
698           char buf[256];
699           struct addrinfo *c = res;
700
701           if (c)
702           {
703             if (c->ai_family == AF_INET)
704             {
705               serv->version = 4;
706               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
707                           "Found %s as address for %s\n",
708                           inet_ntop (c->ai_family,
709                                      &((struct sockaddr_in *) (c->
710                                                                ai_addr))->sin_addr,
711                                      (char *) &buf, 256), hostname);
712               memcpy (serv->v4.ip4address,
713                       &((struct sockaddr_in *) (c->ai_addr))->sin_addr, 4);
714             }
715             else if (c->ai_family == AF_INET6)
716             {
717               serv->version = 6;
718               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
719                           "Found %s as address for %s\n",
720                           inet_ntop (c->ai_family,
721                                      &((struct sockaddr_in6 *) (c->
722                                                                 ai_addr))->sin6_addr,
723                                      (char *) &buf, 256), hostname);
724               memcpy (serv->v6.ip6address,
725                       &((struct sockaddr_in6 *) (c->ai_addr))->sin6_addr, 16);
726             }
727           }
728           else
729           {
730             freeaddrinfo (res);
731             GNUNET_free (serv);
732             continue;
733           }
734           freeaddrinfo (res);
735         }
736       }
737       serv->remote_port = atoi (hostport);
738       if (UDP == proto)
739         GNUNET_assert (GNUNET_OK ==
740                        GNUNET_CONTAINER_multihashmap_put (udp_services,
741                                                           (GNUNET_HashCode *)
742                                                           desc, serv,
743                                                           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
744       else
745         GNUNET_assert (GNUNET_OK ==
746                        GNUNET_CONTAINER_multihashmap_put (tcp_services,
747                                                           (GNUNET_HashCode *)
748                                                           desc, serv,
749                                                           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
750
751     }
752     GNUNET_free (cpy);
753 next:
754     proto = (proto == UDP) ? TCP : UDP;
755   }
756   while (proto != UDP);
757 }
758
759 /**
760  * Start the helper-process
761  *
762  * If cls != NULL it is assumed that this function is called as a result of a dying
763  * helper. cls is then taken as handle to the old helper and is cleaned up.
764  */
765 static void
766 start_helper_and_schedule (void *cls,
767                            const struct GNUNET_SCHEDULER_TaskContext *tc)
768 {
769   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
770     return;
771
772   if (cls != NULL)
773     cleanup_helper (cls);
774   cls = NULL;
775
776   char *ifname;
777   char *ipv6addr;
778   char *ipv6prefix;
779   char *ipv4addr;
780   char *ipv4mask;
781
782   if (GNUNET_SYSERR ==
783       GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IFNAME", &ifname))
784   {
785     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
786                 "No entry 'IFNAME' in configuration!\n");
787     exit (1);
788   }
789
790   if (GNUNET_SYSERR ==
791       GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6ADDR",
792                                              &ipv6addr))
793   {
794     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
795                 "No entry 'IPV6ADDR' in configuration!\n");
796     exit (1);
797   }
798
799   if (GNUNET_SYSERR ==
800       GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6PREFIX",
801                                              &ipv6prefix))
802   {
803     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
804                 "No entry 'IPV6PREFIX' in configuration!\n");
805     exit (1);
806   }
807
808   if (GNUNET_SYSERR ==
809       GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4ADDR",
810                                              &ipv4addr))
811   {
812     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
813                 "No entry 'IPV4ADDR' in configuration!\n");
814     exit (1);
815   }
816
817   if (GNUNET_SYSERR ==
818       GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4MASK",
819                                              &ipv4mask))
820   {
821     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
822                 "No entry 'IPV4MASK' in configuration!\n");
823     exit (1);
824   }
825
826   /* Start the helper
827    * Messages get passed to the function message_token
828    * When the helper dies, this function will be called again with the
829    * helper_handle as cls.
830    */
831   helper_handle =
832       start_helper (ifname, ipv6addr, ipv6prefix, ipv4addr, ipv4mask,
833                     "exit-gnunet", start_helper_and_schedule, message_token,
834                     NULL);
835
836   GNUNET_free (ipv6addr);
837   GNUNET_free (ipv6prefix);
838   GNUNET_free (ipv4addr);
839   GNUNET_free (ipv4mask);
840   GNUNET_free (ifname);
841 }
842
843 static void
844 prepare_ipv4_packet (size_t len, uint16_t pktlen, void *payload,
845                      uint16_t protocol, void *ipaddress, void *tunnel,
846                      struct redirect_state *state, struct ip_pkt *pkt4)
847 {
848   uint32_t tmp, tmp2;
849
850   pkt4->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
851   pkt4->shdr.size = htons (len);
852   pkt4->tun.flags = 0;
853   pkt4->tun.type = htons (0x0800);
854
855   memcpy (&pkt4->data, payload, pktlen);
856
857   pkt4->ip_hdr.version = 4;
858   pkt4->ip_hdr.hdr_lngth = 5;
859   pkt4->ip_hdr.diff_serv = 0;
860   pkt4->ip_hdr.tot_lngth = htons (20 + pktlen);
861   pkt4->ip_hdr.ident = 0;
862   pkt4->ip_hdr.flags = 0;
863   pkt4->ip_hdr.frag_off = 0;
864   pkt4->ip_hdr.ttl = 255;
865   pkt4->ip_hdr.proto = protocol;
866   pkt4->ip_hdr.chks = 0;        /* Will be calculated later */
867
868   memcpy (&tmp, ipaddress, 4);
869   pkt4->ip_hdr.dadr = tmp;
870
871   /* Generate a new src-address */
872   char *ipv4addr;
873   char *ipv4mask;
874
875   GNUNET_assert (GNUNET_OK ==
876                  GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4ADDR",
877                                                         &ipv4addr));
878   GNUNET_assert (GNUNET_OK ==
879                  GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4MASK",
880                                                         &ipv4mask));
881   inet_pton (AF_INET, ipv4addr, &tmp);
882   inet_pton (AF_INET, ipv4mask, &tmp2);
883   GNUNET_free (ipv4addr);
884   GNUNET_free (ipv4mask);
885
886   /* This should be a noop */
887   tmp = tmp & tmp2;
888
889   tmp |= ntohl (*((uint32_t *) tunnel)) & (~tmp2);
890
891   pkt4->ip_hdr.sadr = tmp;
892
893   memcpy (&state->redirect_info.addr, &tmp, 4);
894   if (IPPROTO_UDP == protocol)
895   {
896     struct ip_udp *pkt4_udp = (struct ip_udp *) pkt4;
897
898     state->redirect_info.pt = pkt4_udp->udp_hdr.spt;
899
900     pkt4_udp->udp_hdr.crc = 0;  /* Optional for IPv4 */
901   }
902   else if (IPPROTO_TCP == protocol)
903   {
904     struct ip_tcp *pkt4_tcp = (struct ip_tcp *) pkt4;
905
906     state->redirect_info.pt = pkt4_tcp->tcp_hdr.spt;
907
908     pkt4_tcp->tcp_hdr.crc = 0;
909     uint32_t sum = 0;
910
911     tmp = pkt4->ip_hdr.sadr;
912     sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4);
913     tmp = pkt4->ip_hdr.dadr;
914     sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4);
915
916     tmp = (protocol << 16) | (0xffff & pktlen);
917
918     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "line: %08x, %x \n", tmp,
919                 (0xffff & pktlen));
920
921     tmp = htonl (tmp);
922
923     sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4);
924
925     sum =
926         calculate_checksum_update (sum, (uint16_t *) & pkt4_tcp->tcp_hdr,
927                                    pktlen);
928     pkt4_tcp->tcp_hdr.crc = calculate_checksum_end (sum);
929   }
930
931   pkt4->ip_hdr.chks =
932       calculate_ip_checksum ((uint16_t *) & pkt4->ip_hdr, 5 * 4);
933 }
934
935 static void
936 prepare_ipv6_packet (size_t len, uint16_t pktlen, void *payload,
937                      uint16_t protocol, void *ipaddress, void *tunnel,
938                      struct redirect_state *state, struct ip6_pkt *pkt6)
939 {
940   uint32_t tmp;
941
942   pkt6->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
943   pkt6->shdr.size = htons (len);
944   pkt6->tun.flags = 0;
945
946   pkt6->tun.type = htons (0x86dd);
947
948   memcpy (&pkt6->data, payload, pktlen);
949
950   pkt6->ip6_hdr.version = 6;
951   pkt6->ip6_hdr.nxthdr = protocol;
952   pkt6->ip6_hdr.paylgth = htons (pktlen);
953   pkt6->ip6_hdr.hoplmt = 64;
954
955   memcpy (pkt6->ip6_hdr.dadr, ipaddress, 16);
956
957   /* Generate a new src-address
958    * This takes as much from the address of the tunnel as fits into
959    * the host-mask*/
960   char *ipv6addr;
961   unsigned long long ipv6prefix;
962
963   GNUNET_assert (GNUNET_OK ==
964                  GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6ADDR",
965                                                         &ipv6addr));
966   GNUNET_assert (GNUNET_OK ==
967                  GNUNET_CONFIGURATION_get_value_number (cfg, "exit",
968                                                         "IPV6PREFIX",
969                                                         &ipv6prefix));
970   GNUNET_assert (ipv6prefix < 127);
971   ipv6prefix = (ipv6prefix + 7) / 8;
972
973   inet_pton (AF_INET6, ipv6addr, &pkt6->ip6_hdr.sadr);
974   GNUNET_free (ipv6addr);
975
976   if (ipv6prefix < (16 - sizeof (void *)))
977     ipv6prefix = 16 - sizeof (void *);
978
979   unsigned int offset = ipv6prefix - (16 - sizeof (void *));
980
981   memcpy ((((char *) &pkt6->ip6_hdr.sadr)) + ipv6prefix,
982           ((char *) &tunnel) + offset, 16 - ipv6prefix);
983
984   /* copy the needed information into the state */
985   memcpy (&state->redirect_info.addr, &pkt6->ip6_hdr.sadr, 16);
986
987   if (IPPROTO_UDP == protocol)
988   {
989     struct ip6_udp *pkt6_udp = (struct ip6_udp *) pkt6;
990
991     state->redirect_info.pt = pkt6_udp->udp_hdr.spt;
992
993     pkt6_udp->udp_hdr.crc = 0;
994     uint32_t sum = 0;
995
996     sum =
997         calculate_checksum_update (sum, (uint16_t *) & pkt6_udp->ip6_hdr.sadr,
998                                    16);
999     sum =
1000         calculate_checksum_update (sum, (uint16_t *) & pkt6_udp->ip6_hdr.dadr,
1001                                    16);
1002     tmp = (htons (pktlen) & 0xffff);
1003     sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4);
1004     tmp = htons (((pkt6_udp->ip6_hdr.nxthdr & 0x00ff)));
1005     sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4);
1006
1007     sum =
1008         calculate_checksum_update (sum, (uint16_t *) & pkt6_udp->udp_hdr,
1009                                    ntohs (pkt6_udp->udp_hdr.len));
1010     pkt6_udp->udp_hdr.crc = calculate_checksum_end (sum);
1011   }
1012   else if (IPPROTO_TCP == protocol)
1013   {
1014     struct ip6_tcp *pkt6_tcp = (struct ip6_tcp *) pkt6;
1015
1016     state->redirect_info.pt = pkt6_tcp->tcp_hdr.spt;
1017
1018     pkt6_tcp->tcp_hdr.crc = 0;
1019     uint32_t sum = 0;
1020
1021     sum =
1022         calculate_checksum_update (sum, (uint16_t *) & pkt6->ip6_hdr.sadr, 16);
1023     sum =
1024         calculate_checksum_update (sum, (uint16_t *) & pkt6->ip6_hdr.dadr, 16);
1025     tmp = htonl (pktlen);
1026     sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4);
1027     tmp = htonl (((pkt6->ip6_hdr.nxthdr & 0x000000ff)));
1028     sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4);
1029
1030     sum =
1031         calculate_checksum_update (sum, (uint16_t *) & pkt6_tcp->tcp_hdr,
1032                                    ntohs (pkt6->ip6_hdr.paylgth));
1033     pkt6_tcp->tcp_hdr.crc = calculate_checksum_end (sum);
1034   }
1035 }
1036
1037 /**
1038  * The messages are one GNUNET_HashCode for the service followed by a struct tcp_pkt
1039  */
1040 static int
1041 receive_tcp_service (void *cls
1042                      __attribute__ ((unused)),
1043                      struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx
1044                      __attribute__ ((unused)),
1045                      const struct GNUNET_PeerIdentity *sender
1046                      __attribute__ ((unused)),
1047                      const struct GNUNET_MessageHeader *message,
1048                      const struct GNUNET_ATS_Information *atsi
1049                      __attribute__ ((unused)))
1050 {
1051   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received TCP-Packet\n");
1052   GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1);
1053   struct tcp_pkt *pkt = (struct tcp_pkt *) (desc + 1);
1054   uint16_t pkt_len =
1055       ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) -
1056       sizeof (GNUNET_HashCode);
1057
1058   /** Get the configuration from the services-hashmap.
1059    *
1060    * Which service is needed only depends on the service-descriptor and the
1061    * destination-port
1062    */
1063   uint16_t *tcp_desc = alloca (sizeof (GNUNET_HashCode) + 2);
1064
1065   memcpy (tcp_desc + 1, desc, sizeof (GNUNET_HashCode));
1066   *tcp_desc = ntohs (pkt->dpt);
1067   struct redirect_service *serv =
1068       GNUNET_CONTAINER_multihashmap_get (tcp_services,
1069                                          (GNUNET_HashCode *) tcp_desc);
1070
1071   if (NULL == serv)
1072   {
1073     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "No service found for TCP dpt %d!\n",
1074                 *tcp_desc);
1075     return GNUNET_YES;
1076   }
1077
1078   pkt->dpt = htons (serv->remote_port);
1079
1080   /*
1081    * At this point it would be possible to check against some kind of ACL.
1082    */
1083
1084   char *buf;
1085   size_t len;
1086
1087   /* Prepare the state.
1088    * This will be saved in the hashmap, so that the receiving procedure knows
1089    * through which tunnel this connection has to be routed.
1090    */
1091   struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state));
1092
1093   state->tunnel = tunnel;
1094   state->serv = serv;
1095   state->type = SERVICE;
1096   state->hashmap = tcp_connections;
1097   memcpy (&state->desc, desc, sizeof (GNUNET_HashCode));
1098
1099   len =
1100       sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) +
1101       sizeof (struct ip6_hdr) + pkt_len;
1102   buf = alloca (len);
1103
1104   memset (buf, 0, len);
1105
1106   switch (serv->version)
1107   {
1108   case 4:
1109     prepare_ipv4_packet (len, pkt_len, pkt, IPPROTO_TCP, &serv->v4.ip4address,
1110                          tunnel, state, (struct ip_pkt *) buf);
1111     break;
1112   case 6:
1113     prepare_ipv6_packet (len, pkt_len, pkt, IPPROTO_TCP, &serv->v6.ip6address,
1114                          tunnel, state, (struct ip6_pkt *) buf);
1115
1116     break;
1117   default:
1118     GNUNET_assert (0);
1119     break;
1120   }
1121
1122   hash_redirect_info (&state->hash, &state->redirect_info,
1123                       serv->version == 4 ? 4 : 16);
1124
1125   if (GNUNET_NO ==
1126       GNUNET_CONTAINER_multihashmap_contains (tcp_connections, &state->hash))
1127   {
1128     GNUNET_CONTAINER_multihashmap_put (tcp_connections, &state->hash, state,
1129                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1130
1131     state->heap_node =
1132         GNUNET_CONTAINER_heap_insert (tcp_connections_heap, state,
1133                                       GNUNET_TIME_absolute_get ().abs_value);
1134
1135     if (GNUNET_CONTAINER_heap_get_size (tcp_connections_heap) >
1136         max_tcp_connections)
1137       GNUNET_SCHEDULER_add_now (collect_connections, tcp_connections_heap);
1138   }
1139   else
1140     GNUNET_free (state);
1141
1142   (void) GNUNET_DISK_file_write (helper_handle->fh_to_helper, buf, len);
1143   return GNUNET_YES;
1144 }
1145
1146 static int
1147 receive_tcp_remote (void *cls
1148                     __attribute__ ((unused)), struct GNUNET_MESH_Tunnel *tunnel,
1149                     void **tunnel_ctx
1150                     __attribute__ ((unused)),
1151                     const struct GNUNET_PeerIdentity *sender
1152                     __attribute__ ((unused)),
1153                     const struct GNUNET_MessageHeader *message,
1154                     const struct GNUNET_ATS_Information *atsi
1155                     __attribute__ ((unused)))
1156 {
1157   GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1);
1158   struct tcp_pkt *pkt = (struct tcp_pkt *) (desc + 1);
1159   struct remote_addr *s = (struct remote_addr *) desc;
1160   char *buf;
1161   size_t len;
1162   uint16_t pkt_len =
1163       ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) -
1164       sizeof (GNUNET_HashCode);
1165
1166   struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state));
1167
1168   state->tunnel = tunnel;
1169   state->type = REMOTE;
1170   state->hashmap = tcp_connections;
1171   memcpy (&state->remote, s, sizeof (struct remote_addr));
1172
1173   len =
1174       sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) +
1175       sizeof (struct ip6_hdr) + pkt_len;
1176   buf = alloca (len);
1177
1178   memset (buf, 0, len);
1179
1180   switch (s->addrlen)
1181   {
1182   case 4:
1183     prepare_ipv4_packet (len, pkt_len, pkt, IPPROTO_TCP, &s->addr, tunnel,
1184                          state, (struct ip_pkt *) buf);
1185     break;
1186   case 16:
1187     prepare_ipv6_packet (len, pkt_len, pkt, IPPROTO_TCP, &s->addr, tunnel,
1188                          state, (struct ip6_pkt *) buf);
1189     break;
1190   default:
1191     GNUNET_free (state);
1192     return GNUNET_SYSERR;
1193   }
1194
1195   hash_redirect_info (&state->hash, &state->redirect_info, s->addrlen);
1196
1197   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Packet from remote; hash is %x\n",
1198               *((uint32_t *) & state->hash));
1199
1200   if (GNUNET_NO ==
1201       GNUNET_CONTAINER_multihashmap_contains (tcp_connections, &state->hash))
1202   {
1203     GNUNET_CONTAINER_multihashmap_put (tcp_connections, &state->hash, state,
1204                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1205
1206     state->heap_node =
1207         GNUNET_CONTAINER_heap_insert (tcp_connections_heap, state,
1208                                       GNUNET_TIME_absolute_get ().abs_value);
1209
1210     if (GNUNET_CONTAINER_heap_get_size (tcp_connections_heap) >
1211         max_tcp_connections)
1212       GNUNET_SCHEDULER_add_now (collect_connections, tcp_connections_heap);
1213   }
1214   else
1215     GNUNET_free (state);
1216
1217   (void) GNUNET_DISK_file_write (helper_handle->fh_to_helper, buf, len);
1218   return GNUNET_YES;
1219
1220 }
1221
1222 static int
1223 receive_udp_remote (void *cls
1224                     __attribute__ ((unused)), struct GNUNET_MESH_Tunnel *tunnel,
1225                     void **tunnel_ctx
1226                     __attribute__ ((unused)),
1227                     const struct GNUNET_PeerIdentity *sender
1228                     __attribute__ ((unused)),
1229                     const struct GNUNET_MessageHeader *message,
1230                     const struct GNUNET_ATS_Information *atsi
1231                     __attribute__ ((unused)))
1232 {
1233   GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1);
1234   struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1);
1235   struct remote_addr *s = (struct remote_addr *) desc;
1236   char *buf;
1237   size_t len;
1238
1239   GNUNET_assert (ntohs (pkt->len) ==
1240                  ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) -
1241                  sizeof (GNUNET_HashCode));
1242
1243   /* Prepare the state.
1244    * This will be saved in the hashmap, so that the receiving procedure knows
1245    * through which tunnel this connection has to be routed.
1246    */
1247   struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state));
1248
1249   state->tunnel = tunnel;
1250   state->hashmap = udp_connections;
1251   state->type = REMOTE;
1252   memcpy (&state->remote, s, sizeof (struct remote_addr));
1253
1254   len =
1255       sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) +
1256       sizeof (struct ip6_hdr) + ntohs (pkt->len);
1257   buf = alloca (len);
1258
1259   memset (buf, 0, len);
1260
1261   switch (s->addrlen)
1262   {
1263   case 4:
1264     prepare_ipv4_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, &s->addr,
1265                          tunnel, state, (struct ip_pkt *) buf);
1266     break;
1267   case 16:
1268     prepare_ipv6_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, &s->addr,
1269                          tunnel, state, (struct ip6_pkt *) buf);
1270     break;
1271   default:
1272     GNUNET_assert (0);
1273     break;
1274   }
1275
1276   hash_redirect_info (&state->hash, &state->redirect_info, s->addrlen);
1277
1278   if (GNUNET_NO ==
1279       GNUNET_CONTAINER_multihashmap_contains (udp_connections, &state->hash))
1280   {
1281     GNUNET_CONTAINER_multihashmap_put (udp_connections, &state->hash, state,
1282                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1283
1284     state->heap_node =
1285         GNUNET_CONTAINER_heap_insert (udp_connections_heap, state,
1286                                       GNUNET_TIME_absolute_get ().abs_value);
1287
1288     if (GNUNET_CONTAINER_heap_get_size (udp_connections_heap) >
1289         max_udp_connections)
1290       GNUNET_SCHEDULER_add_now (collect_connections, udp_connections_heap);
1291   }
1292   else
1293     GNUNET_free (state);
1294
1295   (void) GNUNET_DISK_file_write (helper_handle->fh_to_helper, buf, len);
1296   return GNUNET_YES;
1297 }
1298
1299 /**
1300  * The messages are one GNUNET_HashCode for the service, followed by a struct udp_pkt
1301  */
1302 static int
1303 receive_udp_service (void *cls
1304                      __attribute__ ((unused)),
1305                      struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx,
1306                      const struct GNUNET_PeerIdentity *sender
1307                      __attribute__ ((unused)),
1308                      const struct GNUNET_MessageHeader *message,
1309                      const struct GNUNET_ATS_Information *atsi
1310                      __attribute__ ((unused)))
1311 {
1312   GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1);
1313   struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1);
1314
1315   GNUNET_assert (ntohs (pkt->len) ==
1316                  ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) -
1317                  sizeof (GNUNET_HashCode));
1318
1319   /* Get the configuration from the hashmap */
1320   uint16_t *udp_desc = alloca (sizeof (GNUNET_HashCode) + 2);
1321
1322   memcpy (udp_desc + 1, desc, sizeof (GNUNET_HashCode));
1323   *udp_desc = ntohs (pkt->dpt);
1324   struct redirect_service *serv =
1325       GNUNET_CONTAINER_multihashmap_get (udp_services,
1326                                          (GNUNET_HashCode *) udp_desc);
1327
1328   if (NULL == serv)
1329   {
1330     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "No service found for UDP dpt %d!\n",
1331                 *udp_desc);
1332     return GNUNET_YES;
1333   }
1334
1335   pkt->dpt = htons (serv->remote_port);
1336
1337   /*
1338    * At this point it would be possible to check against some kind of ACL.
1339    */
1340
1341   char *buf;
1342   size_t len;
1343
1344   /* Prepare the state.
1345    * This will be saved in the hashmap, so that the receiving procedure knows
1346    * through which tunnel this connection has to be routed.
1347    */
1348   struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state));
1349
1350   state->tunnel = tunnel;
1351   state->serv = serv;
1352   state->type = SERVICE;
1353   state->hashmap = udp_connections;
1354   memcpy (&state->desc, desc, sizeof (GNUNET_HashCode));
1355
1356   len =
1357       sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) +
1358       sizeof (struct ip6_hdr) + ntohs (pkt->len);
1359   buf = alloca (len);
1360
1361   memset (buf, 0, len);
1362
1363   switch (serv->version)
1364   {
1365   case 4:
1366     prepare_ipv4_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP,
1367                          &serv->v4.ip4address, tunnel, state,
1368                          (struct ip_pkt *) buf);
1369     break;
1370   case 6:
1371     prepare_ipv6_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP,
1372                          &serv->v6.ip6address, tunnel, state,
1373                          (struct ip6_pkt *) buf);
1374
1375     break;
1376   default:
1377     GNUNET_assert (0);
1378     break;
1379   }
1380
1381   hash_redirect_info (&state->hash, &state->redirect_info,
1382                       serv->version == 4 ? 4 : 16);
1383
1384   if (GNUNET_NO ==
1385       GNUNET_CONTAINER_multihashmap_contains (udp_connections, &state->hash))
1386   {
1387     GNUNET_CONTAINER_multihashmap_put (udp_connections, &state->hash, state,
1388                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1389
1390     state->heap_node =
1391         GNUNET_CONTAINER_heap_insert (udp_connections_heap, state,
1392                                       GNUNET_TIME_absolute_get ().abs_value);
1393
1394     if (GNUNET_CONTAINER_heap_get_size (udp_connections_heap) >
1395         max_udp_connections)
1396       GNUNET_SCHEDULER_add_now (collect_connections, udp_connections_heap);
1397   }
1398   else
1399     GNUNET_free (state);
1400
1401   (void) GNUNET_DISK_file_write (helper_handle->fh_to_helper, buf, len);
1402   return GNUNET_YES;
1403 }
1404
1405 static void
1406 connect_to_mesh ()
1407 {
1408   int udp, tcp;
1409   int handler_idx, app_idx;
1410
1411   udp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_UDP");
1412   tcp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_TCP");
1413
1414   static struct GNUNET_MESH_MessageHandler handlers[] = {
1415     {receive_udp_service, GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP, 0},
1416     {receive_tcp_service, GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP, 0},
1417     {NULL, 0, 0},
1418     {NULL, 0, 0},
1419     {NULL, 0, 0}
1420   };
1421
1422   static GNUNET_MESH_ApplicationType apptypes[] = {
1423     GNUNET_APPLICATION_TYPE_END,
1424     GNUNET_APPLICATION_TYPE_END,
1425     GNUNET_APPLICATION_TYPE_END
1426   };
1427
1428   app_idx = 0;
1429   handler_idx = 2;
1430
1431   if (GNUNET_YES == udp)
1432   {
1433     handlers[handler_idx].callback = receive_udp_remote;
1434     handlers[handler_idx].expected_size = 0;
1435     handlers[handler_idx].type = GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP;
1436     apptypes[app_idx] = GNUNET_APPLICATION_TYPE_INTERNET_UDP_GATEWAY;
1437     handler_idx++;
1438     app_idx++;
1439   }
1440
1441   if (GNUNET_YES == tcp)
1442   {
1443     handlers[handler_idx].callback = receive_tcp_remote;
1444     handlers[handler_idx].expected_size = 0;
1445     handlers[handler_idx].type = GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP;
1446     apptypes[app_idx] = GNUNET_APPLICATION_TYPE_INTERNET_TCP_GATEWAY;
1447     handler_idx++;
1448     app_idx++;
1449   }
1450
1451   mesh_handle =
1452       GNUNET_MESH_connect (cfg, 42, NULL, new_tunnel, clean_tunnel, handlers,
1453                            apptypes);
1454 }
1455
1456
1457 /**
1458  * @brief Main function that will be run by the scheduler.
1459  *
1460  * @param cls closure
1461  * @param args remaining command-line arguments
1462  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1463  * @param cfg_ configuration
1464  */
1465 static void
1466 run (void *cls, char *const *args __attribute__ ((unused)), const char *cfgfile
1467      __attribute__ ((unused)), const struct GNUNET_CONFIGURATION_Handle *cfg_)
1468 {
1469   cfg = cfg_;
1470
1471   connect_to_mesh ();
1472
1473   udp_connections = GNUNET_CONTAINER_multihashmap_create (65536);
1474   udp_connections_heap =
1475       GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1476   tcp_connections = GNUNET_CONTAINER_multihashmap_create (65536);
1477   tcp_connections_heap =
1478       GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1479   udp_services = GNUNET_CONTAINER_multihashmap_create (65536);
1480   tcp_services = GNUNET_CONTAINER_multihashmap_create (65536);
1481
1482   if (GNUNET_OK !=
1483       GNUNET_CONFIGURATION_get_value_number (cfg, "exit", "MAX_UDP_CONNECTIONS",
1484                                              &max_udp_connections))
1485     max_udp_connections = 1024;
1486   if (GNUNET_OK !=
1487       GNUNET_CONFIGURATION_get_value_number (cfg, "exit", "MAX_TCP_CONNECTIONS",
1488                                              &max_tcp_connections))
1489     max_tcp_connections = 256;
1490   GNUNET_CONFIGURATION_iterate_sections (cfg, read_service_conf, NULL);
1491   GNUNET_SCHEDULER_add_now (start_helper_and_schedule, NULL);
1492   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
1493 }
1494
1495
1496 /**
1497  * The main function
1498  *
1499  * @param argc number of arguments from the command line
1500  * @param argv command line arguments
1501  * @return 0 ok, 1 on error
1502  */
1503 int
1504 main (int argc, char *const *argv)
1505 {
1506   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1507     GNUNET_GETOPT_OPTION_END
1508   };
1509
1510   return (GNUNET_OK ==
1511           GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-exit",
1512                               gettext_noop
1513                               ("Daemon to run to provide an IP exit node for the VPN"),
1514                               options, &run, NULL)) ? ret : 1;
1515 }
1516
1517
1518 /* end of gnunet-daemon-exit.c */