fix usage of mesh_api
[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-vpn-helper-p.h"
31 #include "gnunet-vpn-pretty-print.h"
32 #include "gnunet_common.h"
33 #include <gnunet_os_lib.h>
34 #include "gnunet_protocols.h"
35 #include <gnunet_mesh_service.h>
36 #include "gnunet_client_lib.h"
37 #include "gnunet_container_lib.h"
38 #include "gnunet_constants.h"
39 #include <block_dns.h>
40 #include "gnunet-daemon-vpn-helper.h"
41 #include "gnunet-daemon-vpn-dns.h"
42
43 #include "gnunet-daemon-vpn.h"
44
45 /**
46  * Final status code.
47  */
48 static int ret;
49
50 /**
51  * This hashmap contains the mapping from peer, service-descriptor,
52  * source-port and destination-port to a socket
53  */
54 static struct GNUNET_CONTAINER_MultiHashMap *udp_connections;
55
56 /**
57  * Function scheduled as very last function, cleans up after us
58  *{{{
59  */
60 static void
61 cleanup(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) {
62     GNUNET_assert (0 != (tskctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN));
63
64     /* stop the helper */
65     if (helper_proc != NULL)
66       {
67         if (0 != GNUNET_OS_process_kill (helper_proc, SIGTERM))
68           GNUNET_log_strerror(GNUNET_ERROR_TYPE_WARNING, "kill");
69         GNUNET_OS_process_wait (helper_proc);
70         GNUNET_OS_process_close (helper_proc);
71         helper_proc = NULL;
72       }
73
74     /* close the connection to the service-dns */
75     if (dns_connection != NULL)
76       {
77         GNUNET_CLIENT_disconnect (dns_connection, GNUNET_NO);
78         dns_connection = NULL;
79       }
80
81     if (mesh_handle != NULL)
82       {
83         GNUNET_MESH_disconnect(mesh_handle);
84         mesh_handle = NULL;
85       }
86 }
87 /*}}}*/
88
89 static uint32_t calculate_checksum_update(uint32_t sum, uint16_t *hdr, short len) {
90     for(; len >= 2; len -= 2)
91       sum += *(hdr++);
92     if (len == 1)
93       sum += *((unsigned char*)hdr);
94     return sum;
95 }
96
97 static uint16_t calculate_checksum_end(uint32_t sum) {
98     while (sum >> 16)
99       sum = (sum >> 16) + (sum & 0xFFFF);
100
101     return ~sum;
102 }
103
104 /**
105  * Calculate the checksum of an IPv4-Header
106  */
107 uint16_t
108 calculate_ip_checksum(uint16_t* hdr, short len) {
109     uint32_t sum = calculate_checksum_update(0, hdr, len);
110     return calculate_checksum_end(sum);
111 }
112
113 /**
114  * @return the hash of the IP-Address if a mapping exists, NULL otherwise
115  */
116 GNUNET_HashCode*
117 address_mapping_exists(unsigned char addr[]) {
118     GNUNET_HashCode* key = GNUNET_malloc(sizeof(GNUNET_HashCode));
119     unsigned char* k = (unsigned char*)key;
120     memset(key, 0, sizeof(GNUNET_HashCode));
121     unsigned int i;
122     for (i = 0; i < 16; i++)
123         k[15-i] = addr[i];
124
125     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(hashmap, key))
126       return key;
127     else
128       {
129         GNUNET_free(key);
130         return NULL;
131       }
132 }
133
134 void
135 send_icmp_response(void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc) {
136     struct ip6_icmp* request = cls;
137
138     struct ip6_icmp* response = alloca(ntohs(request->shdr.size));
139     GNUNET_assert(response != NULL);
140     memset(response, 0, ntohs(request->shdr.size));
141
142     response->shdr.size = request->shdr.size;
143     response->shdr.type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
144
145     response->tun.flags = 0;
146     response->tun.type = htons(0x86dd);
147
148     response->ip6_hdr.hoplmt = 255;
149     response->ip6_hdr.paylgth = request->ip6_hdr.paylgth;
150     response->ip6_hdr.nxthdr = 0x3a;
151     response->ip6_hdr.version = 6;
152     memcpy(&response->ip6_hdr.sadr, &request->ip6_hdr.dadr, 16);
153     memcpy(&response->ip6_hdr.dadr, &request->ip6_hdr.sadr, 16);
154
155     response->icmp_hdr.code = 0;
156     response->icmp_hdr.type = 0x81;
157
158     /* Magic, more Magic! */
159     response->icmp_hdr.chks = request->icmp_hdr.chks - 0x1;
160
161     /* Copy the rest of the packet */
162     memcpy(response+1, request+1, ntohs(request->shdr.size) - sizeof(struct ip6_icmp));
163
164     write_to_helper(response, ntohs(response->shdr.size));
165
166     GNUNET_free(request);
167 }
168
169 /**
170  * cls is the pointer to a GNUNET_MessageHeader that is
171  * followed by the service-descriptor and the udp-packet that should be sent;
172  */
173 static size_t
174 send_udp_to_peer_notify_callback (void *cls, size_t size, void *buf)
175 {
176   struct GNUNET_MESH_Tunnel **tunnel = cls;
177   struct GNUNET_MessageHeader *hdr =
178     (struct GNUNET_MessageHeader *) (tunnel + 1);
179   GNUNET_HashCode *hc = (GNUNET_HashCode *) (hdr + 1);
180   struct udp_pkt *udp = (struct udp_pkt *) (hc + 1);
181   hdr->size = htons (sizeof (struct GNUNET_MessageHeader) +
182                      sizeof (GNUNET_HashCode) + ntohs (udp->len));
183   hdr->type = ntohs (GNUNET_MESSAGE_TYPE_SERVICE_UDP);
184   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "send_udp_to_peer_notify_callback: buf = %x; size = %u;\n", buf, size);
185   GNUNET_assert (size >= ntohs (hdr->size));
186   memcpy (buf, hdr, ntohs (hdr->size));
187   size = ntohs(hdr->size);
188   GNUNET_free (cls);
189   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent!\n");
190   return size;
191 }
192
193 unsigned int
194 port_in_ports (uint64_t ports, uint16_t port)
195 {
196   uint16_t *ps = (uint16_t *) & ports;
197   return ps[0] == port || ps[1] == port || ps[2] == port || ps[3] == port;
198 }
199
200 void
201 send_udp_to_peer (void *cls, 
202                   const struct GNUNET_PeerIdentity *peer,
203                   const struct GNUNET_TRANSPORT_ATS_Information *atsi)
204 {
205   if (peer == NULL) return;
206   struct GNUNET_MESH_Tunnel **tunnel = cls;
207   struct GNUNET_MessageHeader *hdr =
208     (struct GNUNET_MessageHeader *) (tunnel + 1);
209   GNUNET_HashCode *hc = (GNUNET_HashCode *) (hdr + 1);
210   struct udp_pkt *udp = (struct udp_pkt *) (hc + 1);
211   GNUNET_MESH_notify_transmit_ready (*tunnel,
212                                      GNUNET_NO,
213                                      42,
214                                      GNUNET_TIME_relative_divide(GNUNET_CONSTANTS_MAX_CORK_DELAY, 2),
215                                      htons (sizeof
216                                             (struct GNUNET_MessageHeader) +
217                                             sizeof (GNUNET_HashCode) +
218                                             ntohs (udp->len)),
219                                      send_udp_to_peer_notify_callback,
220                                      cls);
221 }
222
223 /**
224  * Create a new Address from an answer-packet
225  */
226 void
227 new_ip6addr(char* buf, const GNUNET_HashCode *peer, const GNUNET_HashCode *service_desc) { /* {{{ */
228         memcpy(buf+14, (int[]){htons(0x3412)}, 2);
229         memcpy(buf+8, service_desc, 6);
230         memcpy(buf, peer, 8);
231 }
232 /*}}}*/
233
234 /**
235  * This gets scheduled with cls pointing to an answer_packet and does everything
236  * needed in order to send it to the helper.
237  *
238  * At the moment this means "inventing" and IPv6-Address for .gnunet-services and
239  * doing nothing for "real" services.
240  */
241 void
242 process_answer(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tc) {
243     struct answer_packet* pkt = cls;
244     struct answer_packet_list* list;
245
246     /* This answer is about a .gnunet-service
247      *
248      * It contains an almost complete DNS-Response, we have to fill in the ip
249      * at the offset pkt->addroffset
250      */
251     //FIXME htons?
252     if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_SERVICE)
253       {
254         pkt->subtype = GNUNET_DNS_ANSWER_TYPE_IP;
255
256         GNUNET_HashCode key;
257         memset(&key, 0, sizeof(GNUNET_HashCode));
258         new_ip6addr((char*)&key, &pkt->service_descr.peer, &pkt->service_descr.service_descriptor);
259
260         uint16_t namelen = strlen((char*)pkt->data+12)+1;
261
262         struct map_entry* value = GNUNET_malloc(sizeof(struct map_entry) + namelen);
263         char* name = (char*)(value +1);
264
265         value->namelen = namelen;
266         memcpy(name, pkt->data+12, namelen);
267
268         memcpy(&value->desc, &pkt->service_descr, sizeof(struct GNUNET_vpn_service_descriptor));
269
270         value->additional_ports = 0;
271
272         if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(hashmap,
273                                                            &key,
274                                                            value,
275                                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
276           {
277             GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not store to hashmap\n");
278           }
279
280         /*
281          * Copy the newly generated backward ip-address to the packet
282          */
283         char* c = ((char*)pkt)+ntohs(pkt->addroffset);
284         char* k = (char*)&key;
285         unsigned int i;
286         for (i = 0; i < 16; i++)
287             c[15-i] = k[i];
288
289         list = GNUNET_malloc(htons(pkt->hdr.size) + 2*sizeof(struct answer_packet_list*));
290
291         memcpy(&list->pkt, pkt, htons(pkt->hdr.size));
292
293       }
294     else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_REV)
295       {
296         GNUNET_HashCode key;
297         memset(&key, 0, sizeof key);
298         unsigned char* k = (unsigned char*)&key;
299         unsigned char* s = pkt->data+12;
300         int i = 0;
301         /* Whoever designed the reverse IPv6-lookup is batshit insane */
302         for (i = 0; i < 16; i++)
303           {
304             unsigned char c1 = s[(4*i)+1];
305             unsigned char c2 = s[(4*i)+3];
306             if (c1 <= '9')
307               k[i] = c1 - '0';
308             else
309               k[i] = c1 - 87; /* 87 is the difference between 'a' and 10 */
310             if (c2 <= '9')
311               k[i] += 16*(c2 - '0');
312             else
313               k[i] += 16*(c2 - 87);
314           }
315
316         struct map_entry* map_entry = GNUNET_CONTAINER_multihashmap_get(hashmap, &key);
317         unsigned short offset = ntohs(pkt->addroffset);
318
319         if (map_entry == NULL)
320           {
321             GNUNET_free(pkt);
322             return;
323           }
324
325         unsigned short namelen = htons(map_entry->namelen);
326         char* name = (char*)(map_entry + 1);
327
328         list = GNUNET_malloc(2*sizeof(struct answer_packet_list*) + offset + 2 + ntohs(namelen));
329
330         struct answer_packet* rpkt = &list->pkt;
331
332         /* The offset points to the first byte belonging to the address */
333         memcpy(rpkt, pkt, offset - 1);
334
335         rpkt->subtype = GNUNET_DNS_ANSWER_TYPE_IP;
336         rpkt->hdr.size = ntohs(offset + 2 + ntohs(namelen));
337
338         memcpy(((char*)rpkt)+offset, &namelen, 2);
339         memcpy(((char*)rpkt)+offset+2, name, ntohs(namelen));
340
341       }
342     else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_IP)
343       {
344         list = GNUNET_malloc(htons(pkt->hdr.size) + 2*sizeof(struct answer_packet_list*));
345         memcpy(&list->pkt, pkt, htons(pkt->hdr.size));
346       }
347     else
348       {
349         GNUNET_break(0);
350         GNUNET_free(pkt);
351         return;
352       }
353
354     GNUNET_free(pkt);
355
356     GNUNET_CONTAINER_DLL_insert_after(answer_proc_head, answer_proc_tail, answer_proc_tail, list);
357
358     schedule_helper_write(GNUNET_TIME_UNIT_FOREVER_REL, NULL);
359
360     return;
361 }
362
363 static void
364 add_additional_port (struct map_entry *me, uint16_t port)
365 {
366   uint16_t *ps = (uint16_t *) & me->additional_ports;
367   unsigned int i;
368   for (i = 0; i < 4; i++)
369     {
370       if (ps[i] == 0)
371         {
372           ps[i] = port;
373           break;
374         }
375     }
376 }
377
378 static int
379 receive_udp_back (void *cls, struct GNUNET_MESH_Tunnel* tunnel,
380                   void **tunnel_ctx,
381                   const struct GNUNET_MessageHeader *message,
382                   const struct GNUNET_TRANSPORT_ATS_Information *atsi)
383 {
384   GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1);
385   struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1);
386   char addr[16];
387   const struct GNUNET_PeerIdentity* other = GNUNET_MESH_get_peer(tunnel);
388
389   new_ip6addr(addr, &other->hashPubKey, desc);
390
391   size_t size = sizeof(struct ip6_udp) + ntohs(pkt->len) - 1 - sizeof(struct udp_pkt);
392
393   struct ip6_udp* pkt6 = alloca(size);
394
395   GNUNET_assert(pkt6 != NULL);
396
397   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Relaying calc:%d gnu:%d udp:%d bytes!\n", size, ntohs(message->size), ntohs(pkt->len));
398
399   pkt6->shdr.type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
400   pkt6->shdr.size = htons(size);
401
402   pkt6->tun.flags = 0;
403   pkt6->tun.type = htons(0x86dd);
404
405   pkt6->ip6_hdr.version = 6;
406   pkt6->ip6_hdr.tclass_h = 0;
407   pkt6->ip6_hdr.tclass_l = 0;
408   pkt6->ip6_hdr.flowlbl = 0;
409   pkt6->ip6_hdr.paylgth = pkt->len;
410   pkt6->ip6_hdr.nxthdr = 0x11;
411   pkt6->ip6_hdr.hoplmt = 0xff;
412
413   unsigned int i;
414   for (i = 0; i < 16; i++)
415     pkt6->ip6_hdr.sadr[15-i] = addr[i];
416
417   memcpy(pkt6->ip6_hdr.dadr, (unsigned char[]){0x12, 0x34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 16);
418
419   memcpy(&pkt6->udp_hdr, pkt, ntohs(pkt->len));
420
421   GNUNET_HashCode* key = address_mapping_exists(pkt6->ip6_hdr.sadr);
422   GNUNET_assert (key != NULL);
423
424   struct map_entry *me = GNUNET_CONTAINER_multihashmap_get(hashmap, key);
425
426   GNUNET_free(key);
427
428   GNUNET_assert (me != NULL);
429   GNUNET_assert (me->desc.service_type & htonl(GNUNET_DNS_SERVICE_TYPE_UDP));
430   if (!port_in_ports(me->desc.ports, pkt6->udp_hdr.spt) ||
431       !port_in_ports(me->additional_ports, pkt6->udp_hdr.spt)) {
432       add_additional_port(me, pkt6->udp_hdr.spt);
433   }
434
435   pkt6->udp_hdr.crc = 0;
436   uint32_t sum = 0;
437   sum = calculate_checksum_update(sum, (uint16_t*)&pkt6->ip6_hdr.sadr, 16);
438   sum = calculate_checksum_update(sum, (uint16_t*)&pkt6->ip6_hdr.dadr, 16);
439   uint32_t tmp = (pkt6->udp_hdr.len & 0xffff);
440   sum = calculate_checksum_update(sum, (uint16_t*)&tmp, 4);
441   tmp = htons(((pkt6->ip6_hdr.nxthdr & 0x00ff)));
442   sum = calculate_checksum_update(sum, (uint16_t*)&tmp, 4);
443
444   sum = calculate_checksum_update(sum, (uint16_t*)&pkt6->udp_hdr, ntohs(pkt->len));
445   pkt6->udp_hdr.crc = calculate_checksum_end(sum);
446
447   write_to_helper(pkt6, size);
448
449   return GNUNET_OK;
450 }
451
452 void init_mesh (void* cls, struct GNUNET_MESH_Handle* server, const struct GNUNET_PeerIdentity* my_identity, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pubkey) {
453   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected to MESH, I am %x\n", *((unsigned long*)my_identity));
454 }
455
456 void connect_mesh (void* cls, const struct GNUNET_PeerIdentity* peer, const struct GNUNET_TRANSPORT_ATS_Information *atsi) {
457   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected to peer %x\n", *((unsigned long*)peer));
458 }
459
460 /**
461  * Main function that will be run by the scheduler.
462  *
463  * @param cls closure
464  * @param args remaining command-line arguments
465  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
466  * @param cfg_ configuration
467  */
468 static void
469 run (void *cls,
470      char *const *args,
471      const char *cfgfile,
472      const struct GNUNET_CONFIGURATION_Handle *cfg_)
473 {
474     const static struct GNUNET_MESH_MessageHandler handlers[] = {
475           {receive_udp_back, GNUNET_MESSAGE_TYPE_SERVICE_UDP_BACK, 0},
476           {NULL, 0, 0}
477     };
478     mesh_handle = GNUNET_MESH_connect(cfg_,
479                                       NULL,
480                                       NULL,
481                                       handlers);
482     mst = GNUNET_SERVER_mst_create(&message_token, NULL);
483     cfg = cfg_;
484     restart_hijack = 0;
485     hashmap = GNUNET_CONTAINER_multihashmap_create(65536);
486     udp_connections = GNUNET_CONTAINER_multihashmap_create(65536);
487     GNUNET_SCHEDULER_add_now (connect_to_service_dns, NULL);
488     GNUNET_SCHEDULER_add_now (start_helper_and_schedule, NULL);
489     GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
490 }
491
492 /**
493  * The main function to obtain template from gnunetd.
494  *
495  * @param argc number of arguments from the command line
496  * @param argv command line arguments
497  * @return 0 ok, 1 on error
498  */
499 int
500 main (int argc, char *const *argv) {
501     static const struct GNUNET_GETOPT_CommandLineOption options[] = {
502         GNUNET_GETOPT_OPTION_END
503     };
504
505     return (GNUNET_OK ==
506             GNUNET_PROGRAM_run (argc,
507                                 argv,
508                                 "gnunet-daemon-vpn",
509                                 gettext_noop ("help text"),
510                                 options, &run, NULL)) ? ret : 1;
511 }
512
513 /* end of gnunet-daemon-vpn.c */
514