-consistently use struct GNUNET_HashCode
[oweals/gnunet.git] / src / vpn / gnunet-vpn.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 Christian Grothoff (and other contributing authors)
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 src/vpn/gnunet-vpn.c
23  * @brief Tool to manually request VPN tunnels to be created
24  * @author Christian Grothoff
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_vpn_service.h"
30
31
32 /**
33  * Handle to vpn service.
34  */
35 static struct GNUNET_VPN_Handle *handle;
36
37 /**
38  * Opaque redirection request handle.
39  */
40 static struct GNUNET_VPN_RedirectionRequest *request;
41
42 /**
43  * Option -p: destination peer identity for service
44  */
45 static char *peer_id;
46
47 /**
48  * Option -s: service name (hash to get service descriptor)
49  */
50 static char *service_name;
51
52 /**
53  * Option -i: target IP
54  */
55 static char *target_ip;
56
57 /**
58  * Option -4: IPv4 requested.
59  */
60 static int ipv4;
61
62 /**
63  * Option -6: IPv6 requested.
64  */
65 static int ipv6;
66
67 /**
68  * Option -t: TCP requested.
69  */
70 static int tcp;
71
72 /**
73  * Option -u: UDP requested.
74  */
75 static int udp;
76
77 /**
78  * Selected level of verbosity.
79  */
80 static int verbosity;
81
82 /**
83  * Option '-a':  Notify only once the tunnel is connected?
84  */
85 static int nac;
86
87 /**
88  * Global return value.
89  */
90 static int ret;
91
92 /**
93  * Option '-d': duration of the mapping
94  */
95 static unsigned long long duration = 5 * 60;
96
97
98 /**
99  * Shutdown.
100  */
101 static void
102 do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
103 {
104   if (NULL != request)
105   {
106     GNUNET_VPN_cancel_request (request);
107     request = NULL;
108   }
109   if (NULL != handle)
110   {
111     GNUNET_VPN_disconnect (handle);
112     handle = NULL;
113   }
114   GNUNET_free_non_null (peer_id);
115   GNUNET_free_non_null (service_name);
116   GNUNET_free_non_null (target_ip);
117 }
118
119
120 /**
121  * Callback invoked from the VPN service once a redirection is
122  * available.  Provides the IP address that can now be used to
123  * reach the requested destination.
124  *
125  * @param cls closure
126  * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
127  *                will match 'result_af' from the request
128  * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
129  *                that the VPN allocated for the redirection;
130  *                traffic to this IP will now be redirected to the 
131  *                specified target peer; NULL on error
132  */
133 static void
134 allocation_cb (void *cls,
135                int af,
136                const void *address)
137 {
138   char buf[INET6_ADDRSTRLEN];
139
140   request = NULL;
141   switch (af)
142   {
143   case AF_INET6:
144   case AF_INET:
145     FPRINTF (stdout,
146              "%s\n",
147              inet_ntop (af, address, buf, sizeof (buf)));
148     break;
149   case AF_UNSPEC:
150     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
151                 _("Error creating tunnel\n"));
152     ret = 1;
153     break;
154   default:
155     break;
156   }
157   GNUNET_SCHEDULER_shutdown ();
158 }
159
160
161 /**
162  * Main function that will be run by the scheduler.
163  *
164  * @param cls closure
165  * @param args remaining command-line arguments
166  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
167  * @param cfg configuration
168  */
169 static void
170 run (void *cls, char *const *args, const char *cfgfile,
171      const struct GNUNET_CONFIGURATION_Handle *cfg)
172 {
173   int dst_af;
174   int req_af;
175   struct GNUNET_PeerIdentity peer; 
176   struct GNUNET_HashCode sd;
177   const void *addr;
178   struct in_addr v4;
179   struct in6_addr v6;
180   uint8_t protocol;
181   struct GNUNET_TIME_Absolute etime;
182
183   etime = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
184                                                                            (unsigned int) duration));
185   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
186                                 &do_disconnect, NULL);
187   handle = GNUNET_VPN_connect (cfg);
188   if (NULL == handle)
189     goto error;
190   req_af = AF_UNSPEC;
191   if (ipv4)
192   {
193     if (ipv6)
194     {
195       FPRINTF (stderr, _("Option `%s' makes no sense with option `%s'.\n"),
196                "-4", "-6");
197       goto error;
198     }
199     req_af = AF_INET;
200   }
201   if (ipv6)
202     req_af = AF_INET6;
203   
204   if (NULL == target_ip)
205   {
206     if (NULL == service_name)
207     {
208       FPRINTF (stderr, _("Option `%s' or `%s' is required.\n"),
209                "-i", "-s");
210       goto error;
211     }
212     if (NULL == peer_id)
213     {
214       FPRINTF (stderr, _("Option `%s' is required when using option `%s'.\n"),
215                "-p", "-s");
216       goto error;
217     }
218     if (! (tcp | udp) )
219     {
220       FPRINTF (stderr, _("Option `%s' or `%s' is required when using option `%s'.\n"),
221                "-t", "-u", "-s");
222       goto error;
223     }
224     if (tcp & udp)
225     {
226       FPRINTF (stderr, _("Option `%s' makes no sense with option `%s'.\n"),
227                "-t", "-u");
228       goto error;
229     }
230     if (tcp)
231       protocol = IPPROTO_TCP;
232     if (udp)
233       protocol = IPPROTO_UDP;
234     if (GNUNET_OK !=
235         GNUNET_CRYPTO_hash_from_string (peer_id,
236                                         &peer.hashPubKey))
237     {
238       FPRINTF (stderr, _("`%s' is not a valid peer identifier.\n"),
239                peer_id);
240       goto error;
241     }    
242     GNUNET_CRYPTO_hash (service_name,
243                         strlen (service_name),
244                         &sd);
245     request = GNUNET_VPN_redirect_to_peer (handle,
246                                            req_af,
247                                            protocol,
248                                            &peer,
249                                            &sd,
250                                            nac,
251                                            etime,
252                                            &allocation_cb, NULL);
253   }
254   else
255   {
256     if (1 != inet_pton (AF_INET6, target_ip, &v6))
257     {
258       if (1 != inet_pton (AF_INET, target_ip, &v4))
259       {
260         FPRINTF (stderr, _("`%s' is not a valid IP address.\n"),
261                  target_ip);
262         goto error;
263       }
264       else
265       {
266         dst_af = AF_INET;
267         addr = &v4;
268       }
269     }
270     else
271     {
272       dst_af = AF_INET6;
273       addr = &v6;
274     }    
275     request = GNUNET_VPN_redirect_to_ip (handle,
276                                          req_af,
277                                          dst_af,
278                                          addr,
279                                          nac,
280                                          etime,
281                                          &allocation_cb, NULL);
282   }
283   return;
284
285  error:
286   GNUNET_SCHEDULER_shutdown ();
287   ret = 1;
288 }
289
290
291 int
292 main (int argc, char *const *argv)
293 {
294   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
295     {'4', "ipv4", NULL,
296      gettext_noop ("request that result should be an IPv4 address"),
297      0, &GNUNET_GETOPT_set_one, &ipv4},
298     {'6', "ipv6", NULL,
299      gettext_noop ("request that result should be an IPv6 address"),
300      0, &GNUNET_GETOPT_set_one, &ipv6},
301     {'a', "after-connect", NULL,
302      gettext_noop ("print IP address only after mesh tunnel has been created"),
303      0, &GNUNET_GETOPT_set_one, &ipv6},
304     {'d', "duration", "SECONDS",
305      gettext_noop ("how long should the mapping be valid for new tunnels?"),
306      1, &GNUNET_GETOPT_set_ulong, &duration},
307     {'i', "ip", "IP",
308      gettext_noop ("destination IP for the tunnel"),
309      1, &GNUNET_GETOPT_set_string, &target_ip},
310     {'p', "peer", "PEERID",
311      gettext_noop ("peer offering the service we would like to access"),
312      1, &GNUNET_GETOPT_set_string, &peer_id},
313     {'s', "service", "NAME",
314      gettext_noop ("name of the service we would like to access"),
315      1, &GNUNET_GETOPT_set_string, &service_name},
316     {'t', "tcp", NULL,
317      gettext_noop ("service is offered via TCP"),
318      0, &GNUNET_GETOPT_set_one, &tcp},
319     {'u', "udp", NULL,
320      gettext_noop ("service is offered via UDP"),
321      0, &GNUNET_GETOPT_set_one, &udp},
322
323     GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
324     GNUNET_GETOPT_OPTION_END
325   };
326
327   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
328     return 2;
329
330   return (GNUNET_OK ==
331           GNUNET_PROGRAM_run (argc, argv, "gnunet-vpn",
332                               gettext_noop
333                               ("Setup tunnels via VPN."), options,
334                               &run, NULL)) ? ret : 1;
335 }
336
337
338 /* end of gnunet-vpn.c */