add $(GN_LIBINTL) to Makefile.am (fixes 0005902)
[oweals/gnunet.git] / src / vpn / gnunet-vpn.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
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_tun_lib.h"
30 #include "gnunet_vpn_service.h"
31
32
33 /**
34  * Handle to vpn service.
35  */
36 static struct GNUNET_VPN_Handle *handle;
37
38 /**
39  * Opaque redirection request handle.
40  */
41 static struct GNUNET_VPN_RedirectionRequest *request;
42
43 /**
44  * Option -p: destination peer identity for service
45  */
46 static char *peer_id;
47
48 /**
49  * Option -s: service name (hash to get service descriptor)
50  */
51 static char *service_name;
52
53 /**
54  * Option -i: target IP
55  */
56 static char *target_ip;
57
58 /**
59  * Option -4: IPv4 requested.
60  */
61 static int ipv4;
62
63 /**
64  * Option -6: IPv6 requested.
65  */
66 static int ipv6;
67
68 /**
69  * Option -t: TCP requested.
70  */
71 static int tcp;
72
73 /**
74  * Option -u: UDP requested.
75  */
76 static int udp;
77
78 /**
79  * Selected level of verbosity.
80  */
81 static unsigned int verbosity;
82
83 /**
84  * Global return value.
85  */
86 static int ret;
87
88 /**
89  * Option '-d': duration of the mapping
90  */
91 static struct GNUNET_TIME_Relative duration = { 5 * 60 * 1000 };
92
93
94 /**
95  * Shutdown.
96  */
97 static void
98 do_disconnect (void *cls)
99 {
100   if (NULL != request)
101   {
102     GNUNET_VPN_cancel_request (request);
103     request = NULL;
104   }
105   if (NULL != handle)
106   {
107     GNUNET_VPN_disconnect (handle);
108     handle = NULL;
109   }
110   GNUNET_free_non_null (peer_id);
111   GNUNET_free_non_null (service_name);
112   GNUNET_free_non_null (target_ip);
113 }
114
115
116 /**
117  * Callback invoked from the VPN service once a redirection is
118  * available.  Provides the IP address that can now be used to
119  * reach the requested destination.
120  *
121  * @param cls closure
122  * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
123  *                will match 'result_af' from the request
124  * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
125  *                that the VPN allocated for the redirection;
126  *                traffic to this IP will now be redirected to the
127  *                specified target peer; NULL on error
128  */
129 static void
130 allocation_cb (void *cls, int af, const void *address)
131 {
132   char buf[INET6_ADDRSTRLEN];
133
134   request = NULL;
135   switch (af)
136   {
137   case AF_INET6:
138   case AF_INET:
139     fprintf (stdout, "%s\n", inet_ntop (af, address, buf, sizeof(buf)));
140     break;
141
142   case AF_UNSPEC:
143     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Error creating tunnel\n"));
144     ret = 1;
145     break;
146
147   default:
148     break;
149   }
150   GNUNET_SCHEDULER_shutdown ();
151 }
152
153
154 /**
155  * Main function that will be run by the scheduler.
156  *
157  * @param cls closure
158  * @param args remaining command-line arguments
159  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
160  * @param cfg configuration
161  */
162 static void
163 run (void *cls,
164      char *const *args,
165      const char *cfgfile,
166      const struct GNUNET_CONFIGURATION_Handle *cfg)
167 {
168   int dst_af;
169   int req_af;
170   struct GNUNET_PeerIdentity peer;
171   struct GNUNET_HashCode sd;
172   const void *addr;
173   struct in_addr v4;
174   struct in6_addr v6;
175   uint8_t protocol;
176   struct GNUNET_TIME_Absolute etime;
177
178   etime = GNUNET_TIME_relative_to_absolute (duration);
179   GNUNET_SCHEDULER_add_shutdown (&do_disconnect, NULL);
180   handle = GNUNET_VPN_connect (cfg);
181   if (NULL == handle)
182     goto error;
183   req_af = AF_UNSPEC;
184   if (ipv4)
185   {
186     if (ipv6)
187     {
188       fprintf (stderr,
189                _ ("Option `%s' makes no sense with option `%s'.\n"),
190                "-4",
191                "-6");
192       goto error;
193     }
194     req_af = AF_INET;
195   }
196   if (ipv6)
197     req_af = AF_INET6;
198
199   if (NULL == target_ip)
200   {
201     if (NULL == service_name)
202     {
203       fprintf (stderr, _ ("Option `%s' or `%s' is required.\n"), "-i", "-s");
204       goto error;
205     }
206     if (NULL == peer_id)
207     {
208       fprintf (stderr,
209                _ ("Option `%s' is required when using option `%s'.\n"),
210                "-p",
211                "-s");
212       goto error;
213     }
214     if (! (tcp | udp))
215     {
216       fprintf (stderr,
217                _ ("Option `%s' or `%s' is required when using option `%s'.\n"),
218                "-t",
219                "-u",
220                "-s");
221       goto error;
222     }
223     if (tcp & udp)
224     {
225       fprintf (stderr,
226                _ ("Option `%s' makes no sense with option `%s'.\n"),
227                "-t",
228                "-u");
229       goto error;
230     }
231     if (tcp)
232       protocol = IPPROTO_TCP;
233     if (udp)
234       protocol = IPPROTO_UDP;
235     if (GNUNET_OK !=
236         GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
237                                                     strlen (peer_id),
238                                                     &peer.public_key))
239     {
240       fprintf (stderr, _ ("`%s' is not a valid peer identifier.\n"), peer_id);
241       goto error;
242     }
243     GNUNET_TUN_service_name_to_hash (service_name, &sd);
244     request = GNUNET_VPN_redirect_to_peer (handle,
245                                            req_af,
246                                            protocol,
247                                            &peer,
248                                            &sd,
249                                            etime,
250                                            &allocation_cb,
251                                            NULL);
252   }
253   else
254   {
255     if (1 != inet_pton (AF_INET6, target_ip, &v6))
256     {
257       if (1 != inet_pton (AF_INET, target_ip, &v4))
258       {
259         fprintf (stderr, _ ("`%s' is not a valid IP address.\n"), target_ip);
260         goto error;
261       }
262       else
263       {
264         dst_af = AF_INET;
265         addr = &v4;
266       }
267     }
268     else
269     {
270       dst_af = AF_INET6;
271       addr = &v6;
272     }
273     request = GNUNET_VPN_redirect_to_ip (handle,
274                                          req_af,
275                                          dst_af,
276                                          addr,
277                                          etime,
278                                          &allocation_cb,
279                                          NULL);
280   }
281   return;
282
283 error:
284   GNUNET_SCHEDULER_shutdown ();
285   ret = 1;
286 }
287
288
289 int
290 main (int argc, char *const *argv)
291 {
292   struct GNUNET_GETOPT_CommandLineOption options[] =
293   { GNUNET_GETOPT_option_flag ('4',
294                                "ipv4",
295                                gettext_noop (
296                                  "request that result should be an IPv4 address"),
297                                &ipv4),
298
299     GNUNET_GETOPT_option_flag ('6',
300                                "ipv6",
301                                gettext_noop (
302                                  "request that result should be an IPv6 address"),
303                                &ipv6),
304
305     GNUNET_GETOPT_option_relative_time (
306       'd',
307       "duration",
308       "TIME",
309       gettext_noop ("how long should the mapping be valid for new tunnels?"),
310       &duration),
311
312     GNUNET_GETOPT_option_string ('i',
313                                  "ip",
314                                  "IP",
315                                  gettext_noop (
316                                    "destination IP for the tunnel"),
317                                  &target_ip),
318
319     GNUNET_GETOPT_option_string (
320       'p',
321       "peer",
322       "PEERID",
323       gettext_noop ("peer offering the service we would like to access"),
324       &peer_id),
325
326     GNUNET_GETOPT_option_string ('s',
327                                  "service",
328                                  "NAME",
329                                  gettext_noop (
330                                    "name of the service we would like to access"),
331                                  &service_name),
332
333     GNUNET_GETOPT_option_flag ('t',
334                                "tcp",
335                                gettext_noop ("service is offered via TCP"),
336                                &tcp),
337
338     GNUNET_GETOPT_option_flag ('u',
339                                "udp",
340                                gettext_noop ("service is offered via UDP"),
341                                &udp),
342
343     GNUNET_GETOPT_option_verbose (&verbosity),
344
345     GNUNET_GETOPT_OPTION_END };
346
347   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
348     return 2;
349
350   ret =
351     (GNUNET_OK == GNUNET_PROGRAM_run (argc,
352                                       argv,
353                                       "gnunet-vpn",
354                                       gettext_noop ("Setup tunnels via VPN."),
355                                       options,
356                                       &run,
357                                       NULL))
358     ? ret
359     : 1;
360   GNUNET_free ((void *) argv);
361   return ret;
362 }
363
364
365 /* end of gnunet-vpn.c */