debug the vpn
[oweals/gnunet.git] / src / vpn / gnunet-daemon-vpn.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-vpn.c
23  * @brief
24  * @author Philipp Toelke
25  */
26 #include "platform.h"
27 #include "gnunet_getopt_lib.h"
28 #include "gnunet_program_lib.h"
29 #include "gnunet-vpn-packet.h"
30 #include "gnunet_common.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_applications.h"
33 #include <gnunet_mesh_service.h>
34 #include "gnunet_client_lib.h"
35 #include "gnunet_container_lib.h"
36 #include "gnunet_constants.h"
37 #include <block_dns.h>
38 #include "gnunet-daemon-vpn-helper.h"
39 #include "gnunet-daemon-vpn-dns.h"
40 #include "gnunet-daemon-vpn.h"
41 #include "gnunet-vpn-checksum.h"
42
43 const struct GNUNET_CONFIGURATION_Handle *cfg;
44 struct GNUNET_MESH_Handle *mesh_handle;
45 struct GNUNET_CONTAINER_MultiHashMap* hashmap;
46 static struct GNUNET_CONTAINER_Heap *heap;
47
48 /**
49  * If there are at least this many address-mappings, old ones will be removed
50  */
51 static long long unsigned int max_mappings = 200;
52
53 /**
54  * Final status code.
55  */
56 static int ret;
57
58 /**
59  * This hashmap contains the mapping from peer, service-descriptor,
60  * source-port and destination-port to a socket
61  */
62 static struct GNUNET_CONTAINER_MultiHashMap *udp_connections;
63
64 /**
65  * Function scheduled as very last function, cleans up after us
66  *{{{
67  */
68 static void
69 cleanup(void* cls __attribute__((unused)), const struct GNUNET_SCHEDULER_TaskContext* tskctx) {
70     GNUNET_assert (0 != (tskctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN));
71
72     /* stop the helper */
73     cleanup_helper(helper_handle);
74
75     /* close the connection to the service-dns */
76     if (dns_connection != NULL)
77       {
78         GNUNET_CLIENT_disconnect (dns_connection, GNUNET_NO);
79         dns_connection = NULL;
80       }
81
82     if (mesh_handle != NULL)
83       {
84         GNUNET_MESH_disconnect(mesh_handle);
85         mesh_handle = NULL;
86       }
87 }
88 /*}}}*/
89
90 /**
91  * @return the hash of the IP-Address if a mapping exists, NULL otherwise
92  */
93 GNUNET_HashCode*
94 address_mapping_exists(unsigned char addr[]) {
95     GNUNET_HashCode* key = GNUNET_malloc(sizeof(GNUNET_HashCode));
96     unsigned char* k = (unsigned char*)key;
97     memset(key, 0, sizeof(GNUNET_HashCode));
98     unsigned int i;
99     for (i = 0; i < 16; i++)
100         k[15-i] = addr[i];
101
102     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(hashmap, key))
103       return key;
104     else
105       {
106         GNUNET_free(key);
107         return NULL;
108       }
109 }
110
111 static void
112 collect_mappings(void* cls __attribute__((unused)), const struct GNUNET_SCHEDULER_TaskContext* tc) {
113     if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
114       return;
115
116     struct map_entry* me = GNUNET_CONTAINER_heap_remove_root(heap);
117
118     /* This is free()ed memory! */
119     me->heap_node = NULL;
120
121     /* FIXME! GNUNET_MESH_close_tunnel(me->tunnel); */
122
123     GNUNET_CONTAINER_multihashmap_remove(hashmap, &me->hash, me);
124
125     GNUNET_free(me);
126 }
127
128 void
129 send_icmp_response(void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc) {
130     if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
131       return;
132
133     struct ip6_icmp* request = cls;
134
135     struct ip6_icmp* response = alloca(ntohs(request->shdr.size));
136     GNUNET_assert(response != NULL);
137     memset(response, 0, ntohs(request->shdr.size));
138
139     response->shdr.size = request->shdr.size;
140     response->shdr.type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
141
142     response->tun.flags = 0;
143     response->tun.type = htons(0x86dd);
144
145     response->ip6_hdr.hoplmt = 255;
146     response->ip6_hdr.paylgth = request->ip6_hdr.paylgth;
147     response->ip6_hdr.nxthdr = 0x3a;
148     response->ip6_hdr.version = 6;
149     memcpy(&response->ip6_hdr.sadr, &request->ip6_hdr.dadr, 16);
150     memcpy(&response->ip6_hdr.dadr, &request->ip6_hdr.sadr, 16);
151
152     response->icmp_hdr.code = 0;
153     response->icmp_hdr.type = 0x81;
154
155     /* Magic, more Magic! */
156     response->icmp_hdr.chks = request->icmp_hdr.chks - 0x1;
157
158     /* Copy the rest of the packet */
159     memcpy(response+1, request+1, ntohs(request->shdr.size) - sizeof(struct ip6_icmp));
160
161     write_to_helper(response, ntohs(response->shdr.size));
162
163     GNUNET_free(request);
164 }
165
166 /**
167  * cls is the pointer to a GNUNET_MessageHeader that is
168  * followed by the service-descriptor and the packet that should be sent;
169  */
170 static size_t
171 send_pkt_to_peer_notify_callback (void *cls, size_t size, void *buf)
172 {
173   struct GNUNET_MESH_Tunnel **tunnel = cls;
174   struct GNUNET_MessageHeader *hdr =
175     (struct GNUNET_MessageHeader *) (tunnel + 1);
176   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "send_pkt_to_peer_notify_callback: buf = %x; size = %u;\n", buf, size);
177   GNUNET_assert (size >= ntohs (hdr->size));
178   memcpy (buf, hdr, ntohs (hdr->size));
179   size = ntohs(hdr->size);
180   GNUNET_free (cls);
181   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent!\n");
182   return size;
183 }
184
185 unsigned int
186 port_in_ports (uint64_t ports, uint16_t port)
187 {
188   uint16_t *ps = (uint16_t *) & ports;
189   return ps[0] == port || ps[1] == port || ps[2] == port || ps[3] == port;
190 }
191
192 void
193 send_pkt_to_peer (void *cls, 
194                   const struct GNUNET_PeerIdentity *peer,
195                   const struct GNUNET_TRANSPORT_ATS_Information *atsi __attribute__((unused)))
196 {
197   /* peer == NULL means that all peers in this request are connected */
198   if (peer == NULL) return;
199   struct GNUNET_MESH_Tunnel **tunnel = cls;
200   struct GNUNET_MessageHeader *hdr =
201     (struct GNUNET_MessageHeader *) (tunnel + 1);
202
203   GNUNET_assert(NULL != tunnel);
204   GNUNET_assert(NULL != *tunnel);
205
206   GNUNET_MESH_notify_transmit_ready (*tunnel,
207                                      GNUNET_NO,
208                                      42,
209                                      GNUNET_TIME_relative_divide(GNUNET_CONSTANTS_MAX_CORK_DELAY, 2),
210                                      (const struct GNUNET_PeerIdentity *)NULL,
211                                      ntohs(hdr->size),
212                                      send_pkt_to_peer_notify_callback,
213                                      cls);
214 }
215
216 /**
217  * Create a new Address from an answer-packet
218  */
219 void
220 new_ip6addr(unsigned char* buf, const GNUNET_HashCode *peer, const GNUNET_HashCode *service_desc) { /* {{{ */
221     char* ipv6addr;
222     unsigned long long ipv6prefix;
223     GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "vpn", "IPV6ADDR", &ipv6addr));
224     GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "vpn", "IPV6PREFIX", &ipv6prefix));
225     GNUNET_assert(ipv6prefix < 127);
226     ipv6prefix = (ipv6prefix + 7)/8;
227
228     inet_pton (AF_INET6, ipv6addr, buf);
229     GNUNET_free(ipv6addr);
230
231     int peer_length = 16 - ipv6prefix - 6;
232     if (peer_length <= 0)
233       peer_length = 0;
234
235     int service_length = 16 - ipv6prefix - peer_length;
236     if (service_length <= 0)
237       service_length = 0;
238
239     memcpy(buf+ipv6prefix, service_desc, service_length);
240     memcpy(buf+ipv6prefix+service_length, peer, peer_length);
241 }
242 /*}}}*/
243
244
245 /**
246  * Create a new Address from an answer-packet
247  */
248 void
249 new_ip6addr_remote (unsigned char *buf, unsigned char *addr, char addrlen)
250 {                               /* {{{ */
251   char *ipv6addr;
252   unsigned long long ipv6prefix;
253   GNUNET_assert (GNUNET_OK ==
254                  GNUNET_CONFIGURATION_get_value_string (cfg, "vpn",
255                                                         "IPV6ADDR",
256                                                         &ipv6addr));
257   GNUNET_assert (GNUNET_OK ==
258                  GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
259                                                         "IPV6PREFIX",
260                                                         &ipv6prefix));
261   GNUNET_assert (ipv6prefix < 127);
262   ipv6prefix = (ipv6prefix + 7) / 8;
263
264   inet_pton (AF_INET6, ipv6addr, buf);
265   GNUNET_free (ipv6addr);
266
267   int local_length = 16 - ipv6prefix;
268
269   memcpy (buf + ipv6prefix, addr, GNUNET_MAX (addrlen, local_length));
270 }
271 /*}}}*/
272
273 /**
274  * This gets scheduled with cls pointing to an answer_packet and does everything
275  * needed in order to send it to the helper.
276  *
277  * At the moment this means "inventing" and IPv6-Address for .gnunet-services and
278  * doing nothing for "real" services.
279  */
280 void
281 process_answer(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tc) {
282     if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
283       return;
284
285     struct answer_packet* pkt = cls;
286     struct answer_packet_list* list;
287
288     /* This answer is about a .gnunet-service
289      *
290      * It contains an almost complete DNS-Response, we have to fill in the ip
291      * at the offset pkt->addroffset
292      */
293     if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_SERVICE)
294       {
295         pkt->subtype = GNUNET_DNS_ANSWER_TYPE_IP;
296
297         GNUNET_HashCode key;
298         memset(&key, 0, sizeof(GNUNET_HashCode));
299
300         unsigned char* c = ((unsigned char*)pkt)+ntohs(pkt->addroffset);
301         unsigned char* k = (unsigned char*)&key;
302         new_ip6addr(c, &pkt->service_descr.peer, &pkt->service_descr.service_descriptor);
303         /*
304          * Copy the newly generated ip-address to the key backwarts (as only the first part is hashed)
305          */
306         unsigned int i;
307         for (i = 0; i < 16; i++)
308             k[15-i] = c[i];
309
310         uint16_t namelen = strlen((char*)pkt->data+12)+1;
311
312         struct map_entry* value = GNUNET_malloc(sizeof(struct map_entry) + namelen);
313         char* name = (char*)(value +1);
314
315         value->namelen = namelen;
316         memcpy(name, pkt->data+12, namelen);
317
318         memcpy(&value->desc, &pkt->service_descr, sizeof(struct GNUNET_vpn_service_descriptor));
319
320         memset(value->additional_ports, 0, 8192);
321
322         memcpy(&value->hash, &key, sizeof(GNUNET_HashCode));
323
324         if (GNUNET_NO ==
325             GNUNET_CONTAINER_multihashmap_contains (hashmap, &key))
326           {
327             GNUNET_CONTAINER_multihashmap_put (hashmap, &key, value,
328                                                GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
329
330             value->heap_node = GNUNET_CONTAINER_heap_insert (heap, value,
331                                                              GNUNET_TIME_absolute_get ().abs_value);
332             if (GNUNET_CONTAINER_heap_get_size(heap) > max_mappings)
333               GNUNET_SCHEDULER_add_now(collect_mappings, NULL);
334           }
335         else
336           GNUNET_free(value);
337
338
339         list = GNUNET_malloc(htons(pkt->hdr.size) + 2*sizeof(struct answer_packet_list*));
340
341         memcpy(&list->pkt, pkt, htons(pkt->hdr.size));
342
343       }
344     else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_REV)
345       {
346         GNUNET_HashCode key;
347         memset(&key, 0, sizeof key);
348         unsigned char* k = (unsigned char*)&key;
349         unsigned char* s = pkt->data+12;
350         int i = 0;
351         /* Whoever designed the reverse IPv6-lookup is batshit insane */
352         for (i = 0; i < 16; i++)
353           {
354             unsigned char c1 = s[(4*i)+1];
355             unsigned char c2 = s[(4*i)+3];
356             if (c1 <= '9')
357               k[i] = c1 - '0';
358             else
359               k[i] = c1 - 87; /* 87 is the difference between 'a' and 10 */
360             if (c2 <= '9')
361               k[i] += 16*(c2 - '0');
362             else
363               k[i] += 16*(c2 - 87);
364           }
365
366         struct map_entry* map_entry = GNUNET_CONTAINER_multihashmap_get(hashmap, &key);
367         uint16_t offset = ntohs(pkt->addroffset);
368
369         if (map_entry == NULL)
370           {
371             GNUNET_free(pkt);
372             return;
373           }
374
375         GNUNET_CONTAINER_heap_update_cost (heap, map_entry->heap_node,
376                                            GNUNET_TIME_absolute_get ().abs_value);
377
378
379         unsigned short namelen = htons(map_entry->namelen);
380         char* name = (char*)(map_entry + 1);
381
382         list = GNUNET_malloc(2*sizeof(struct answer_packet_list*) + offset + 2 + ntohs(namelen));
383
384         struct answer_packet* rpkt = &list->pkt;
385
386         /* The offset points to the first byte belonging to the address */
387         memcpy(rpkt, pkt, offset - 1);
388
389         rpkt->subtype = GNUNET_DNS_ANSWER_TYPE_IP;
390         rpkt->hdr.size = ntohs(offset + 2 + ntohs(namelen));
391
392         memcpy(((char*)rpkt)+offset, &namelen, 2);
393         memcpy(((char*)rpkt)+offset+2, name, ntohs(namelen));
394
395       }
396     else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_IP)
397       {
398         list = GNUNET_malloc(htons(pkt->hdr.size) + 2*sizeof(struct answer_packet_list*));
399         memcpy(&list->pkt, pkt, htons(pkt->hdr.size));
400       }
401     else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_REMOTE)
402       {
403         pkt->subtype = GNUNET_DNS_ANSWER_TYPE_IP;
404
405         GNUNET_HashCode key;
406         memset(&key, 0, sizeof(GNUNET_HashCode));
407
408         unsigned char* c = ((unsigned char*)pkt)+ntohs(pkt->addroffset);
409         new_ip6addr_remote(c, pkt->addr, pkt->addrsize);
410         unsigned char* k = (unsigned char*)&key;
411         /*
412          * Copy the newly generated ip-address to the key backwards (as only the first part is used in the hash-table)
413          */
414         unsigned int i;
415         for (i = 0; i < 16; i++)
416             k[15-i] = c[i];
417
418         uint16_t namelen = strlen((char*)pkt->data+12)+1;
419
420         struct map_entry* value = GNUNET_malloc(sizeof(struct map_entry) + namelen);
421         char* name = (char*)(value +1);
422
423         value->namelen = namelen;
424         memcpy(name, pkt->data+12, namelen);
425
426         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Setting addrlen to %d\n", pkt->addrsize);
427         value->addrlen = pkt->addrsize;
428         memcpy(&value->addr, &pkt->addr, pkt->addrsize);
429         memset(value->additional_ports, 0, 8192);
430
431         memcpy(&value->hash, &key, sizeof(GNUNET_HashCode));
432
433         if (GNUNET_NO ==
434             GNUNET_CONTAINER_multihashmap_contains (hashmap, &key))
435           {
436             GNUNET_CONTAINER_multihashmap_put (hashmap, &key, value,
437                                                GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
438             value->heap_node = GNUNET_CONTAINER_heap_insert (heap, value,
439                                                              GNUNET_TIME_absolute_get ().abs_value);
440             if (GNUNET_CONTAINER_heap_get_size(heap) > max_mappings)
441               GNUNET_SCHEDULER_add_now(collect_mappings, NULL);
442           }
443         else
444           GNUNET_free(value);
445
446         list = GNUNET_malloc(htons(pkt->hdr.size) + 2*sizeof(struct answer_packet_list*));
447
448         memcpy(&list->pkt, pkt, htons(pkt->hdr.size));
449       }
450     else
451       {
452         GNUNET_break(0);
453         GNUNET_free(pkt);
454         return;
455       }
456
457     GNUNET_free(pkt);
458
459     GNUNET_CONTAINER_DLL_insert_after(answer_proc_head, answer_proc_tail, answer_proc_tail, list);
460
461     schedule_helper_write(GNUNET_TIME_UNIT_FOREVER_REL, NULL);
462
463     return;
464 }
465
466 /**
467  * Sets a bit active in a bitArray.
468  *
469  * @param bitArray memory area to set the bit in
470  * @param bitIdx which bit to set
471  */
472 void
473 setBit (char *bitArray, unsigned int bitIdx)
474 {
475   size_t arraySlot;
476   unsigned int targetBit;
477
478   arraySlot = bitIdx / 8;
479   targetBit = (1L << (bitIdx % 8));
480   bitArray[arraySlot] |= targetBit;
481 }
482
483 /**
484  * Clears a bit from bitArray.
485  *
486  * @param bitArray memory area to set the bit in
487  * @param bitIdx which bit to unset
488  */
489 void
490 clearBit (char *bitArray, unsigned int bitIdx)
491 {
492   size_t slot;
493   unsigned int targetBit;
494
495   slot = bitIdx / 8;
496   targetBit = (1L << (bitIdx % 8));
497   bitArray[slot] = bitArray[slot] & (~targetBit);
498 }
499
500 /**
501  * Checks if a bit is active in the bitArray
502  *
503  * @param bitArray memory area to set the bit in
504  * @param bitIdx which bit to test
505  * @return GNUNET_YES if the bit is set, GNUNET_NO if not.
506  */
507 int
508 testBit (char *bitArray, unsigned int bitIdx)
509 {
510   size_t slot;
511   unsigned int targetBit;
512
513   slot = bitIdx / 8;
514   targetBit = (1L << (bitIdx % 8));
515   if (bitArray[slot] & targetBit)
516     return GNUNET_YES;
517   else
518     return GNUNET_NO;
519 }
520
521 /**
522  * @brief Add the port to the list of additional ports in the map_entry
523  *
524  * @param me the map_entry
525  * @param port the port in host-byte-order
526  */
527 static void
528 add_additional_port (struct map_entry *me, uint16_t port)
529 {
530   setBit(me->additional_ports, port);
531 }
532
533 static int
534 receive_udp_back (void *cls __attribute__((unused)), struct GNUNET_MESH_Tunnel* tunnel,
535                   void **tunnel_ctx __attribute__((unused)),
536                   const struct GNUNET_PeerIdentity *sender __attribute__((unused)),
537                   const struct GNUNET_MessageHeader *message,
538                   const struct GNUNET_TRANSPORT_ATS_Information *atsi __attribute__((unused)))
539 {
540   GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1);
541   struct remote_addr* s = (struct remote_addr*)desc;
542   struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1);
543   const struct GNUNET_PeerIdentity* other = GNUNET_MESH_get_peer(tunnel);
544
545   size_t size = sizeof(struct ip6_udp) + ntohs(pkt->len) - 1 - sizeof(struct udp_pkt);
546
547   struct ip6_udp* pkt6 = alloca(size);
548
549   GNUNET_assert(pkt6 != NULL);
550
551   if (ntohs(message->type) == GNUNET_MESSAGE_TYPE_SERVICE_UDP_BACK)
552     new_ip6addr(pkt6->ip6_hdr.sadr, &other->hashPubKey, desc);
553   else
554     new_ip6addr_remote(pkt6->ip6_hdr.sadr, s->addr, s->addrlen);
555
556   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Relaying calc:%d gnu:%d udp:%d bytes!\n", size, ntohs(message->size), ntohs(pkt->len));
557
558   pkt6->shdr.type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
559   pkt6->shdr.size = htons(size);
560
561   pkt6->tun.flags = 0;
562   pkt6->tun.type = htons(0x86dd);
563
564   pkt6->ip6_hdr.version = 6;
565   pkt6->ip6_hdr.tclass_h = 0;
566   pkt6->ip6_hdr.tclass_l = 0;
567   pkt6->ip6_hdr.flowlbl = 0;
568   pkt6->ip6_hdr.paylgth = pkt->len;
569   pkt6->ip6_hdr.nxthdr = 0x11;
570   pkt6->ip6_hdr.hoplmt = 0xff;
571
572   {
573     char* ipv6addr;
574     GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "vpn", "IPV6ADDR", &ipv6addr));
575     inet_pton (AF_INET6, ipv6addr, pkt6->ip6_hdr.dadr);
576     GNUNET_free(ipv6addr);
577   }
578   memcpy(&pkt6->udp_hdr, pkt, ntohs(pkt->len));
579
580   GNUNET_HashCode* key = address_mapping_exists(pkt6->ip6_hdr.sadr);
581   GNUNET_assert (key != NULL);
582
583   struct map_entry *me = GNUNET_CONTAINER_multihashmap_get(hashmap, key);
584   GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node,
585                                      GNUNET_TIME_absolute_get ().abs_value);
586
587   GNUNET_free(key);
588
589   GNUNET_assert (me != NULL);
590   if (ntohs(message->type) == GNUNET_MESSAGE_TYPE_SERVICE_UDP_BACK)
591     {
592       GNUNET_assert (me->desc.service_type & htonl(GNUNET_DNS_SERVICE_TYPE_UDP));
593       if (!port_in_ports(me->desc.ports, pkt6->udp_hdr.spt) &&
594           !testBit(me->additional_ports, ntohs(pkt6->udp_hdr.spt))) {
595           add_additional_port(me, ntohs(pkt6->udp_hdr.spt));
596       }
597     }
598
599   pkt6->udp_hdr.crc = 0;
600   uint32_t sum = 0;
601   sum = calculate_checksum_update(sum, (uint16_t*)&pkt6->ip6_hdr.sadr, 16);
602   sum = calculate_checksum_update(sum, (uint16_t*)&pkt6->ip6_hdr.dadr, 16);
603   uint32_t tmp = (pkt6->udp_hdr.len & 0xffff);
604   sum = calculate_checksum_update(sum, (uint16_t*)&tmp, 4);
605   tmp = htons(((pkt6->ip6_hdr.nxthdr & 0x00ff)));
606   sum = calculate_checksum_update(sum, (uint16_t*)&tmp, 4);
607
608   sum = calculate_checksum_update(sum, (uint16_t*)&pkt6->udp_hdr, ntohs(pkt->len));
609   pkt6->udp_hdr.crc = calculate_checksum_end(sum);
610
611   write_to_helper(pkt6, size);
612
613   return GNUNET_OK;
614 }
615
616 static int
617 receive_tcp_back (void *cls __attribute__((unused)), struct GNUNET_MESH_Tunnel* tunnel,
618                   void **tunnel_ctx __attribute__((unused)),
619                   const struct GNUNET_PeerIdentity *sender __attribute__((unused)),
620                   const struct GNUNET_MessageHeader *message,
621                   const struct GNUNET_TRANSPORT_ATS_Information *atsi __attribute__((unused)))
622 {
623   GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1);
624   struct remote_addr* s = (struct remote_addr*)desc;
625   struct tcp_pkt *pkt = (struct tcp_pkt *) (desc + 1);
626   const struct GNUNET_PeerIdentity* other = GNUNET_MESH_get_peer(tunnel);
627
628   size_t pktlen = ntohs(message->size) - sizeof(struct GNUNET_MessageHeader) - sizeof(GNUNET_HashCode);
629   size_t size = pktlen + sizeof(struct ip6_tcp) - 1;
630
631   struct ip6_tcp* pkt6 = alloca(size);
632   memset(pkt6, 0, size);
633
634   GNUNET_assert(pkt6 != NULL);
635
636   if (ntohs(message->type) == GNUNET_MESSAGE_TYPE_SERVICE_TCP_BACK)
637     new_ip6addr(pkt6->ip6_hdr.sadr, &other->hashPubKey, desc);
638   else
639     new_ip6addr_remote(pkt6->ip6_hdr.sadr, s->addr, s->addrlen);
640
641   pkt6->shdr.type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
642   pkt6->shdr.size = htons(size);
643
644   pkt6->tun.flags = 0;
645   pkt6->tun.type = htons(0x86dd);
646
647   pkt6->ip6_hdr.version = 6;
648   pkt6->ip6_hdr.tclass_h = 0;
649   pkt6->ip6_hdr.tclass_l = 0;
650   pkt6->ip6_hdr.flowlbl = 0;
651   pkt6->ip6_hdr.paylgth = htons(pktlen);
652   pkt6->ip6_hdr.nxthdr = 0x06;
653   pkt6->ip6_hdr.hoplmt = 0xff;
654
655   {
656     char* ipv6addr;
657     GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "vpn", "IPV6ADDR", &ipv6addr));
658     inet_pton (AF_INET6, ipv6addr, pkt6->ip6_hdr.dadr);
659     GNUNET_free(ipv6addr);
660   }
661   memcpy(&pkt6->tcp_hdr, pkt, pktlen);
662
663   GNUNET_HashCode* key = address_mapping_exists(pkt6->ip6_hdr.sadr);
664   GNUNET_assert (key != NULL);
665
666   struct map_entry *me = GNUNET_CONTAINER_multihashmap_get(hashmap, key);
667   GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node,
668                                      GNUNET_TIME_absolute_get ().abs_value);
669
670   GNUNET_free(key);
671
672   GNUNET_assert (me != NULL);
673   if (ntohs(message->type) == GNUNET_MESSAGE_TYPE_SERVICE_UDP_BACK)
674     GNUNET_assert (me->desc.service_type & htonl(GNUNET_DNS_SERVICE_TYPE_TCP));
675
676   pkt6->tcp_hdr.crc = 0;
677   uint32_t sum = 0;
678   uint32_t tmp;
679   sum =
680     calculate_checksum_update (sum, (uint16_t *) & pkt6->ip6_hdr.sadr, 16);
681   sum =
682     calculate_checksum_update (sum, (uint16_t *) & pkt6->ip6_hdr.dadr, 16);
683   tmp = htonl(pktlen);
684   sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4);
685   tmp = htonl (((pkt6->ip6_hdr.nxthdr & 0x000000ff)));
686   sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4);
687
688   sum =
689     calculate_checksum_update (sum, (uint16_t *) & pkt6->tcp_hdr,
690                                ntohs (pkt6->ip6_hdr.paylgth));
691   pkt6->tcp_hdr.crc = calculate_checksum_end (sum);
692
693   write_to_helper(pkt6, size);
694
695   return GNUNET_OK;
696 }
697
698 /**
699  * Main function that will be run by the scheduler.
700  *
701  * @param cls closure
702  * @param args remaining command-line arguments
703  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
704  * @param cfg_ configuration
705  */
706 static void
707 run (void *cls,
708      char *const *args __attribute__((unused)),
709      const char *cfgfilep __attribute__((unused)),
710      const struct GNUNET_CONFIGURATION_Handle *cfg_)
711 {
712     static const struct GNUNET_MESH_MessageHandler handlers[] = {
713           {receive_udp_back, GNUNET_MESSAGE_TYPE_SERVICE_UDP_BACK, 0},
714           {receive_tcp_back, GNUNET_MESSAGE_TYPE_SERVICE_TCP_BACK, 0},
715           {receive_udp_back, GNUNET_MESSAGE_TYPE_REMOTE_UDP_BACK, 0},
716           {receive_tcp_back, GNUNET_MESSAGE_TYPE_REMOTE_TCP_BACK, 0},
717           {NULL, 0, 0}
718     };
719
720     static const GNUNET_MESH_ApplicationType types[] = {
721         GNUNET_APPLICATION_TYPE_END
722     };
723
724     mesh_handle = GNUNET_MESH_connect(cfg_,
725                                       NULL,
726                                       NULL,
727                                       handlers,
728                                       types);
729     cfg = cfg_;
730     restart_hijack = 0;
731     hashmap = GNUNET_CONTAINER_multihashmap_create(65536);
732     heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
733     GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPINGg",
734                                            &max_mappings);
735     udp_connections = GNUNET_CONTAINER_multihashmap_create(65536);
736     GNUNET_SCHEDULER_TaskIdentifier conn_task = GNUNET_SCHEDULER_add_now (connect_to_service_dns, NULL);
737     GNUNET_SCHEDULER_add_after (conn_task, start_helper_and_schedule, NULL);
738     GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
739 }
740
741 /**
742  * The main function to obtain template from gnunetd.
743  *
744  * @param argc number of arguments from the command line
745  * @param argv command line arguments
746  * @return 0 ok, 1 on error
747  */
748 int
749 main (int argc, char *const *argv) {
750     static const struct GNUNET_GETOPT_CommandLineOption options[] = {
751         GNUNET_GETOPT_OPTION_END
752     };
753
754     return (GNUNET_OK ==
755             GNUNET_PROGRAM_run (argc,
756                                 argv,
757                                 "vpn",
758                                 gettext_noop ("help text"),
759                                 options, &run, NULL)) ? ret : 1;
760 }
761
762 /* end of gnunet-daemon-vpn.c */
763