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