-convert vpn/exit/pt to use new CADET ports
[oweals/gnunet.git] / src / vpn / vpn_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2016 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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file vpn/vpn_api.c
23  * @brief library to access the VPN service and tell it how to redirect traffic
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_vpn_service.h"
28 #include "vpn.h"
29
30
31 /**
32  * Opaque VPN handle
33  */
34 struct GNUNET_VPN_Handle
35 {
36   /**
37    * Configuration we use.
38    */
39   const struct GNUNET_CONFIGURATION_Handle *cfg;
40
41   /**
42    * Connection to VPN service.
43    */
44   struct GNUNET_MQ_Handle *mq;
45
46   /**
47    * Head of list of active redirection requests.
48    */
49   struct GNUNET_VPN_RedirectionRequest *rr_head;
50
51   /**
52    * Tail of list of active redirection requests.
53    */
54   struct GNUNET_VPN_RedirectionRequest *rr_tail;
55
56   /**
57    * Identifier of a reconnect task.
58    */
59   struct GNUNET_SCHEDULER_Task *rt;
60
61   /**
62    * How long do we wait until we try to reconnect?
63    */
64   struct GNUNET_TIME_Relative backoff;
65
66   /**
67    * ID of the last request that was submitted to the service.
68    */
69   uint64_t request_id_gen;
70
71 };
72
73
74 /**
75  * Opaque redirection request handle.
76  */
77 struct GNUNET_VPN_RedirectionRequest
78 {
79   /**
80    * Element in DLL.
81    */
82   struct GNUNET_VPN_RedirectionRequest *next;
83
84   /**
85    * Element in DLL.
86    */
87   struct GNUNET_VPN_RedirectionRequest *prev;
88
89   /**
90    * Pointer to the VPN struct.
91    */
92   struct GNUNET_VPN_Handle *vh;
93
94   /**
95    * Target IP address for the redirection, or NULL for
96    * redirection to service.  Allocated after this struct.
97    */
98   const void *addr;
99
100   /**
101    * Function to call with the designated IP address.
102    */
103   GNUNET_VPN_AllocationCallback cb;
104
105   /**
106    * Closure for @e cb.
107    */
108   void *cb_cls;
109
110   /**
111    * For service redirection, identity of the peer offering the service.
112    */
113   struct GNUNET_PeerIdentity peer;
114
115   /**
116    * For service redirection, service descriptor.
117    */
118   struct GNUNET_HashCode serv;
119
120   /**
121    * At what time should the created service mapping expire?
122    */
123   struct GNUNET_TIME_Absolute expiration_time;
124
125   /**
126    * non-zero if this request has been sent to the service.
127    */
128   uint64_t request_id;
129
130   /**
131    * Desired address family for the result.
132    */
133   int result_af;
134
135   /**
136    * Address family of @e addr.  AF_INET or AF_INET6.
137    */
138   int addr_af;
139
140   /**
141    * For service redirection, IPPROT_UDP or IPPROTO_TCP.
142    */
143   uint8_t protocol;
144
145 };
146
147
148 /**
149  * Disconnect from the service (communication error) and reconnect later.
150  *
151  * @param vh handle to reconnect.
152  */
153 static void
154 reconnect (struct GNUNET_VPN_Handle *vh);
155
156
157 /**
158  * Check a #GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP message from the
159  * VPN service.
160  *
161  * @param cls the `struct GNUNET_VPN_Handle`
162  * @param rm message received
163  * @return #GNUNET_OK if @a rm is well-formed
164  */
165 static int
166 check_use_ip (void *cls,
167               const struct RedirectToIpResponseMessage *rm)
168 {
169   size_t alen;
170   int af;
171
172   af = (int) ntohl (rm->result_af);
173   switch (af)
174   {
175   case AF_UNSPEC:
176     alen = 0;
177     break;
178   case AF_INET:
179     alen = sizeof (struct in_addr);
180     break;
181   case AF_INET6:
182     alen = sizeof (struct in6_addr);
183     break;
184   default:
185     GNUNET_break (0);
186     return GNUNET_SYSERR;
187   }
188   if ( (ntohs (rm->header.size) != alen + sizeof (*rm)) ||
189        (0 == rm->request_id) )
190   {
191     GNUNET_break (0);
192     return GNUNET_SYSERR;
193   }
194   return GNUNET_OK;
195 }
196
197
198 /**
199  * Handle a #GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP message from the
200  * VPN service.
201  *
202  * @param cls the `struct GNUNET_VPN_Handle`
203  * @param rm message received
204  */
205 static void
206 handle_use_ip (void *cls,
207                const struct RedirectToIpResponseMessage *rm)
208 {
209   struct GNUNET_VPN_Handle *vh = cls;
210   struct GNUNET_VPN_RedirectionRequest *rr;
211   int af;
212
213   af = (int) ntohl (rm->result_af);
214   for (rr = vh->rr_head; NULL != rr; rr = rr->next)
215   {
216     if (rr->request_id == rm->request_id)
217     {
218       GNUNET_CONTAINER_DLL_remove (vh->rr_head,
219                                    vh->rr_tail,
220                                    rr);
221       rr->cb (rr->cb_cls,
222               af,
223               (af == AF_UNSPEC) ? NULL : &rm[1]);
224       GNUNET_free (rr);
225       break;
226     }
227   }
228 }
229
230
231 /**
232  * Add a request to our request queue and transmit it.
233  *
234  * @param rr request to queue and transmit.
235  */
236 static void
237 send_request (struct GNUNET_VPN_RedirectionRequest *rr)
238 {
239   struct GNUNET_VPN_Handle *vh = rr->vh;
240   struct RedirectToIpRequestMessage *rip;
241   struct RedirectToServiceRequestMessage *rs;
242   struct GNUNET_MQ_Envelope *env;
243   size_t alen;
244
245   if (NULL == vh->mq)
246     return;
247   if (NULL == rr->addr)
248   {
249     env = GNUNET_MQ_msg (rs,
250                          GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE);
251     rs->reserved = htonl (0);
252     rs->expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time);
253     rs->protocol = htonl (rr->protocol);
254     rs->result_af = htonl (rr->result_af);
255     rs->target = rr->peer;
256     rs->service_descriptor = rr->serv;
257     rs->request_id = rr->request_id = ++vh->request_id_gen;
258   }
259   else
260   {
261     switch (rr->addr_af)
262     {
263     case AF_INET:
264       alen = sizeof (struct in_addr);
265       break;
266     case AF_INET6:
267       alen = sizeof (struct in6_addr);
268       break;
269     default:
270       GNUNET_assert (0);
271       return;
272     }
273     env = GNUNET_MQ_msg_extra (rip,
274                                alen,
275                                GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP);
276     rip->reserved = htonl (0);
277     rip->expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time);
278     rip->result_af = htonl (rr->result_af);
279     rip->addr_af = htonl (rr->addr_af);
280     rip->request_id = rr->request_id = ++vh->request_id_gen;
281     GNUNET_memcpy (&rip[1],
282                    rr->addr,
283                    alen);
284   }
285   GNUNET_MQ_send (vh->mq,
286                   env);
287 }
288
289
290 /**
291  * Generic error handler, called with the appropriate error code and
292  * the same closure specified at the creation of the message queue.
293  * Not every message queue implementation supports an error handler.
294  *
295  * @param cls closure with the `struct GNUNET_VPN_Handle *`
296  * @param error error code
297  */
298 static void
299 mq_error_handler (void *cls,
300                   enum GNUNET_MQ_Error error)
301 {
302   struct GNUNET_VPN_Handle *vh = cls;
303
304   reconnect (vh);
305 }
306
307
308 /**
309  * Connect to the VPN service and start again to transmit our requests.
310  *
311  * @param cls the `struct GNUNET_VPN_Handle *`
312  */
313 static void
314 connect_task (void *cls)
315 {
316   struct GNUNET_VPN_Handle *vh = cls;
317   GNUNET_MQ_hd_var_size (use_ip,
318                          GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP,
319                          struct RedirectToIpResponseMessage);
320   struct GNUNET_MQ_MessageHandler handlers[] = {
321     make_use_ip_handler (cls),
322     GNUNET_MQ_handler_end ()
323   };
324   struct GNUNET_VPN_RedirectionRequest *rr;
325
326   vh->rt = NULL;
327   vh->mq = GNUNET_CLIENT_connecT (vh->cfg,
328                                   "vpn",
329                                   handlers,
330                                   &mq_error_handler,
331                                   vh);
332   if (NULL == vh->mq)
333     return;
334   for (rr = vh->rr_head; NULL != rr; rr = rr->next)
335     send_request (rr);
336 }
337
338
339 /**
340  * Disconnect from the service (communication error) and reconnect later.
341  *
342  * @param vh handle to reconnect.
343  */
344 static void
345 reconnect (struct GNUNET_VPN_Handle *vh)
346 {
347   struct GNUNET_VPN_RedirectionRequest *rr;
348
349   GNUNET_MQ_destroy (vh->mq);
350   vh->mq = NULL;
351   vh->request_id_gen = 0;
352   for (rr = vh->rr_head; NULL != rr; rr = rr->next)
353     rr->request_id = 0;
354   vh->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS,
355                                           GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (vh->backoff, 2),
356                                                                     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)));
357   vh->rt = GNUNET_SCHEDULER_add_delayed (vh->backoff,
358                                          &connect_task,
359                                          vh);
360 }
361
362
363 /**
364  * Cancel redirection request with the service.
365  *
366  * @param rr request to cancel
367  */
368 void
369 GNUNET_VPN_cancel_request (struct GNUNET_VPN_RedirectionRequest *rr)
370 {
371   struct GNUNET_VPN_Handle *vh;
372
373   vh = rr->vh;
374   GNUNET_CONTAINER_DLL_remove (vh->rr_head,
375                                vh->rr_tail,
376                                rr);
377   GNUNET_free (rr);
378 }
379
380
381 /**
382  * Tell the VPN that a forwarding to a particular peer offering a
383  * particular service is requested.  The VPN is to reserve a
384  * particular IP for the redirection and return it.  The VPN will
385  * begin the redirection as soon as possible and maintain it as long
386  * as it is actively used and keeping it is feasible.  Given resource
387  * limitations, the longest inactive mappings will be destroyed.
388  *
389  * @param vh VPN handle
390  * @param result_af desired address family for the returned allocation
391  *                  can also be AF_UNSPEC
392  * @param protocol protocol, IPPROTO_UDP or IPPROTO_TCP
393  * @param peer target peer for the redirection
394  * @param serv service descriptor to give to the peer
395  * @param expiration_time at what time should the redirection expire?
396  *        (this should not impact connections that are active at that time)
397  * @param cb function to call with the IP
398  * @param cb_cls closure for @a cb
399  * @return handle to cancel the request (means the callback won't be
400  *         invoked anymore; the mapping may or may not be established
401  *         anyway)
402  */
403 struct GNUNET_VPN_RedirectionRequest *
404 GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *vh,
405                              int result_af,
406                              uint8_t protocol,
407                              const struct GNUNET_PeerIdentity *peer,
408                              const struct GNUNET_HashCode *serv,
409                              struct GNUNET_TIME_Absolute expiration_time,
410                              GNUNET_VPN_AllocationCallback cb,
411                              void *cb_cls)
412 {
413   struct GNUNET_VPN_RedirectionRequest *rr;
414
415   rr = GNUNET_new (struct GNUNET_VPN_RedirectionRequest);
416   rr->vh = vh;
417   rr->cb = cb;
418   rr->cb_cls = cb_cls;
419   rr->peer = *peer;
420   rr->serv = *serv;
421   rr->expiration_time = expiration_time;
422   rr->result_af = result_af;
423   rr->protocol = protocol;
424   GNUNET_CONTAINER_DLL_insert_tail (vh->rr_head,
425                                     vh->rr_tail,
426                                     rr);
427   send_request (rr);
428   return rr;
429 }
430
431
432 /**
433  * Tell the VPN that forwarding to the Internet via some exit node is
434  * requested.  Note that both UDP and TCP traffic will be forwarded,
435  * but possibly to different exit nodes.  The VPN is to reserve a
436  * particular IP for the redirection and return it.  The VPN will
437  * begin the redirection as soon as possible and maintain it as long
438  * as it is actively used and keeping it is feasible.  Given resource
439  * limitations, the longest inactive mappings will be destroyed.
440  *
441  * @param vh VPN handle
442  * @param result_af desired address family for the returned allocation
443  * @param addr_af address family for @a addr, AF_INET or AF_INET6
444  * @param addr destination IP address on the Internet; destination
445  *             port is to be taken from the VPN packet itself
446  * @param expiration_time at what time should the redirection expire?
447  *        (this should not impact connections that are active at that time)
448  * @param cb function to call with the IP
449  * @param cb_cls closure for @a cb
450  * @return handle to cancel the request (means the callback won't be
451  *         invoked anymore; the mapping may or may not be established
452  *         anyway)
453  */
454 struct GNUNET_VPN_RedirectionRequest *
455 GNUNET_VPN_redirect_to_ip (struct GNUNET_VPN_Handle *vh,
456                            int result_af,
457                            int addr_af,
458                            const void *addr,
459                            struct GNUNET_TIME_Absolute expiration_time,
460                            GNUNET_VPN_AllocationCallback cb,
461                            void *cb_cls)
462 {
463   struct GNUNET_VPN_RedirectionRequest *rr;
464   size_t alen;
465
466   switch (addr_af)
467   {
468   case AF_INET:
469     alen = sizeof (struct in_addr);
470     break;
471   case AF_INET6:
472     alen = sizeof (struct in6_addr);
473     break;
474   default:
475     GNUNET_break (0);
476     return NULL;
477   }
478   rr = GNUNET_malloc (sizeof (struct GNUNET_VPN_RedirectionRequest) + alen);
479   rr->vh = vh;
480   rr->addr = &rr[1];
481   rr->cb = cb;
482   rr->cb_cls = cb_cls;
483   rr->expiration_time = expiration_time;
484   rr->result_af = result_af;
485   rr->addr_af = addr_af;
486   GNUNET_memcpy (&rr[1],
487           addr,
488           alen);
489   GNUNET_CONTAINER_DLL_insert_tail (vh->rr_head,
490                                     vh->rr_tail,
491                                     rr);
492   send_request (rr);
493   return rr;
494 }
495
496
497 /**
498  * Connect to the VPN service
499  *
500  * @param cfg configuration to use
501  * @return VPN handle
502  */
503 struct GNUNET_VPN_Handle *
504 GNUNET_VPN_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
505 {
506   struct GNUNET_VPN_Handle *vh
507     = GNUNET_new (struct GNUNET_VPN_Handle);
508
509   vh->cfg = cfg;
510   connect_task (vh);
511   if (NULL == vh->mq)
512   {
513     GNUNET_free (vh);
514     return NULL;
515   }
516   return vh;
517 }
518
519
520 /**
521  * Disconnect from the VPN service.
522  *
523  * @param vh VPN handle
524  */
525 void
526 GNUNET_VPN_disconnect (struct GNUNET_VPN_Handle *vh)
527 {
528   GNUNET_assert (NULL == vh->rr_head);
529   if (NULL != vh->mq)
530   {
531     GNUNET_MQ_destroy (vh->mq);
532     vh->mq = NULL;
533   }
534   if (NULL != vh->rt)
535   {
536     GNUNET_SCHEDULER_cancel (vh->rt);
537     vh->rt = NULL;
538   }
539   GNUNET_free (vh);
540 }
541
542 /* end of vpn_api.c */