aboutsummaryrefslogtreecommitdiff
path: root/src/pt/test_gnunet_vpn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pt/test_gnunet_vpn.c')
-rw-r--r--src/pt/test_gnunet_vpn.c519
1 files changed, 0 insertions, 519 deletions
diff --git a/src/pt/test_gnunet_vpn.c b/src/pt/test_gnunet_vpn.c
deleted file mode 100644
index ab197b60d..000000000
--- a/src/pt/test_gnunet_vpn.c
+++ /dev/null
@@ -1,519 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2007, 2009, 2011, 2012 Christian Grothoff
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 test_gnunet_vpn.c
23 * @brief testcase for tunneling HTTP over the GNUnet VPN
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27/* Just included for the right curl.h */
28#include "gnunet_curl_lib.h"
29#include <microhttpd.h>
30#include "gnunet_vpn_service.h"
31#include "gnunet_testing_lib.h"
32#include "gnunet_mhd_compat.h"
33
34#define PORT 48080
35
36#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
37
38
39/**
40 * Return value for 'main'.
41 */
42static int global_ret;
43
44static struct GNUNET_VPN_Handle *vpn;
45
46static struct MHD_Daemon *mhd;
47
48static struct GNUNET_SCHEDULER_Task *mhd_task_id;
49
50static struct GNUNET_SCHEDULER_Task *curl_task_id;
51
52static struct GNUNET_SCHEDULER_Task *timeout_task_id;
53
54static struct GNUNET_VPN_RedirectionRequest *rr;
55
56static CURL *curl;
57
58static CURLM *multi;
59
60static char *url;
61
62/**
63 * IP address of the ultimate destination.
64 */
65static const char *dest_ip;
66
67/**
68 * Address family of the dest_ip.
69 */
70static int dest_af;
71
72/**
73 * Address family to use by the curl client.
74 */
75static int src_af;
76
77
78struct CBC
79{
80 char buf[1024];
81 size_t pos;
82};
83
84static struct CBC cbc;
85
86
87static size_t
88copy_buffer (void *ptr, size_t size, size_t nmemb, void *ctx)
89{
90 struct CBC *cbc = ctx;
91
92 if (cbc->pos + size * nmemb > sizeof(cbc->buf))
93 return 0; /* overflow */
94 GNUNET_memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
95 cbc->pos += size * nmemb;
96 return size * nmemb;
97}
98
99
100static MHD_RESULT
101mhd_ahc (void *cls,
102 struct MHD_Connection *connection,
103 const char *url,
104 const char *method,
105 const char *version,
106 const char *upload_data,
107 size_t *upload_data_size,
108 void **unused)
109{
110 static int ptr;
111 struct MHD_Response *response;
112 int ret;
113
114 if (0 != strcmp ("GET", method))
115 return MHD_NO; /* unexpected method */
116 if (&ptr != *unused)
117 {
118 *unused = &ptr;
119 return MHD_YES;
120 }
121 *unused = NULL;
122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
123 "MHD sends response for request to URL `%s'\n", url);
124 response =
125 MHD_create_response_from_buffer (strlen (url), (void *) url,
126 MHD_RESPMEM_MUST_COPY);
127 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
128 MHD_destroy_response (response);
129 if (ret == MHD_NO)
130 abort ();
131 return ret;
132}
133
134
135static void
136do_shutdown (void *cls)
137{
138 if (NULL != mhd_task_id)
139 {
140 GNUNET_SCHEDULER_cancel (mhd_task_id);
141 mhd_task_id = NULL;
142 }
143 if (NULL != curl_task_id)
144 {
145 GNUNET_SCHEDULER_cancel (curl_task_id);
146 curl_task_id = NULL;
147 }
148 if (NULL != timeout_task_id)
149 {
150 GNUNET_SCHEDULER_cancel (timeout_task_id);
151 timeout_task_id = NULL;
152 }
153 if (NULL != mhd)
154 {
155 MHD_stop_daemon (mhd);
156 mhd = NULL;
157 }
158 if (NULL != rr)
159 {
160 GNUNET_VPN_cancel_request (rr);
161 rr = NULL;
162 }
163 if (NULL != vpn)
164 {
165 GNUNET_VPN_disconnect (vpn);
166 vpn = NULL;
167 }
168 GNUNET_free (url);
169 url = NULL;
170}
171
172
173/**
174 * Function to run the HTTP client.
175 */
176static void
177curl_main (void *cls)
178{
179 fd_set rs;
180 fd_set ws;
181 fd_set es;
182 int max;
183 struct GNUNET_NETWORK_FDSet nrs;
184 struct GNUNET_NETWORK_FDSet nws;
185 struct GNUNET_TIME_Relative delay;
186 long timeout;
187 int running;
188 struct CURLMsg *msg;
189
190 curl_task_id = NULL;
191 max = 0;
192 FD_ZERO (&rs);
193 FD_ZERO (&ws);
194 FD_ZERO (&es);
195 curl_multi_perform (multi, &running);
196 if (running == 0)
197 {
198 GNUNET_assert (NULL != (msg = curl_multi_info_read (multi, &running)));
199 if (msg->msg == CURLMSG_DONE)
200 {
201 if (msg->data.result != CURLE_OK)
202 {
203 fprintf (stderr, "%s failed at %s:%d: `%s'\n", "curl_multi_perform",
204 __FILE__, __LINE__, curl_easy_strerror (msg->data.result));
205 global_ret = 1;
206 }
207 }
208 curl_multi_remove_handle (multi, curl);
209 curl_multi_cleanup (multi);
210 curl_easy_cleanup (curl);
211 curl = NULL;
212 multi = NULL;
213 if (cbc.pos != strlen ("/hello_world"))
214 {
215 GNUNET_break (0);
216 global_ret = 2;
217 }
218 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
219 {
220 GNUNET_break (0);
221 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
222 "You might want to check if your host-based firewall is blocking the connections.\n");
223 global_ret = 3;
224 }
225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download complete, shutting down!\n");
226 GNUNET_SCHEDULER_shutdown ();
227 return;
228 }
229 GNUNET_assert (CURLM_OK == curl_multi_fdset (multi, &rs, &ws, &es, &max));
230 if ((CURLM_OK != curl_multi_timeout (multi, &timeout)) || (-1 == timeout))
231 delay = GNUNET_TIME_UNIT_SECONDS;
232 else
233 delay =
234 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
235 (unsigned int) timeout);
236 GNUNET_NETWORK_fdset_copy_native (&nrs, &rs, max + 1);
237 GNUNET_NETWORK_fdset_copy_native (&nws, &ws, max + 1);
238 curl_task_id =
239 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, delay,
240 &nrs, &nws, &curl_main, NULL);
241}
242
243
244/**
245 * Callback invoked from the VPN service once a redirection is
246 * available. Provides the IP address that can now be used to
247 * reach the requested destination (in our case, the MHD server)
248 *
249 * @param cls closure
250 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
251 * will match 'result_af' from the request
252 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
253 * that the VPN allocated for the redirection;
254 * traffic to this IP will now be redirected to the
255 * specified target peer; NULL on error
256 */
257static void
258allocation_cb (void *cls, int af, const void *address)
259{
260 char ips[INET6_ADDRSTRLEN];
261
262 rr = NULL;
263 if (src_af != af)
264 {
265 fprintf (stderr,
266 "VPN failed to allocate appropriate address\n");
267 GNUNET_SCHEDULER_shutdown ();
268 return;
269 }
270 if (AF_INET6 == af)
271 GNUNET_asprintf (&url,
272 "http://[%s]:%u/hello_world",
273 inet_ntop (af,
274 address,
275 ips,
276 sizeof(ips)),
277 (unsigned int) PORT);
278 else
279 GNUNET_asprintf (&url,
280 "http://%s:%u/hello_world",
281 inet_ntop (af,
282 address,
283 ips,
284 sizeof(ips)),
285 (unsigned int) PORT);
286 curl = curl_easy_init ();
287 curl_easy_setopt (curl, CURLOPT_URL, url);
288 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, &copy_buffer);
289 curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbc);
290 curl_easy_setopt (curl, CURLOPT_FAILONERROR, 1);
291 curl_easy_setopt (curl, CURLOPT_TIMEOUT, 150L);
292 curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, 15L);
293 curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1);
294 curl_easy_setopt (curl, CURLOPT_VERBOSE, 0);
295
296 multi = curl_multi_init ();
297 GNUNET_assert (multi != NULL);
298 GNUNET_assert (CURLM_OK == curl_multi_add_handle (multi, curl));
299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
300 "Beginning HTTP download from `%s'\n",
301 url);
302 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
303 &curl_main,
304 NULL);
305}
306
307
308/**
309 * Function to keep the HTTP server running.
310 */
311static void
312mhd_main (void);
313
314
315static void
316mhd_task (void *cls)
317{
318 mhd_task_id = NULL;
319 MHD_run (mhd);
320 mhd_main ();
321}
322
323
324static void
325do_timeout (void *cls)
326{
327 timeout_task_id = NULL;
328 GNUNET_SCHEDULER_shutdown ();
329 GNUNET_break (0);
330 global_ret = 1;
331}
332
333
334static void
335mhd_main ()
336{
337 struct GNUNET_NETWORK_FDSet nrs;
338 struct GNUNET_NETWORK_FDSet nws;
339 fd_set rs;
340 fd_set ws;
341 fd_set es;
342 int max_fd;
343 unsigned MHD_LONG_LONG timeout;
344 struct GNUNET_TIME_Relative delay;
345
346 GNUNET_assert (NULL == mhd_task_id);
347 FD_ZERO (&rs);
348 FD_ZERO (&ws);
349 FD_ZERO (&es);
350 max_fd = -1;
351 GNUNET_assert (MHD_YES == MHD_get_fdset (mhd, &rs, &ws, &es, &max_fd));
352 if (MHD_YES == MHD_get_timeout (mhd, &timeout))
353 delay =
354 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
355 (unsigned int) timeout);
356 else
357 delay = GNUNET_TIME_UNIT_FOREVER_REL;
358 GNUNET_NETWORK_fdset_copy_native (&nrs, &rs, max_fd + 1);
359 GNUNET_NETWORK_fdset_copy_native (&nws, &ws, max_fd + 1);
360 mhd_task_id =
361 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, delay,
362 &nrs, &nws, &mhd_task, NULL);
363}
364
365
366static void
367run (void *cls,
368 const struct GNUNET_CONFIGURATION_Handle *cfg,
369 struct GNUNET_TESTING_Peer *peer)
370{
371 struct in_addr v4;
372 struct in6_addr v6;
373 void *addr;
374 enum MHD_FLAG flags;
375
376 vpn = GNUNET_VPN_connect (cfg);
377 GNUNET_assert (NULL != vpn);
378 flags = MHD_USE_DEBUG;
379 if (AF_INET6 == dest_af)
380 flags |= MHD_USE_IPv6;
381 mhd =
382 MHD_start_daemon (flags, PORT, NULL, NULL, &mhd_ahc, NULL,
383 MHD_OPTION_END);
384
385
386 GNUNET_assert (NULL != mhd);
387 mhd_main ();
388 addr = NULL;
389 switch (dest_af)
390 {
391 case AF_INET:
392 GNUNET_assert (1 == inet_pton (dest_af, dest_ip, &v4));
393 addr = &v4;
394 break;
395
396 case AF_INET6:
397 GNUNET_assert (1 == inet_pton (dest_af, dest_ip, &v6));
398 addr = &v6;
399 break;
400
401 default:
402 GNUNET_assert (0);
403 }
404 rr = GNUNET_VPN_redirect_to_ip (vpn, src_af, dest_af, addr,
405 GNUNET_TIME_UNIT_FOREVER_ABS, &allocation_cb,
406 NULL);
407 timeout_task_id =
408 GNUNET_SCHEDULER_add_delayed (TIMEOUT,
409 &do_timeout,
410 NULL);
411 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
412 NULL);
413}
414
415
416int
417main (int argc, char *const *argv)
418{
419 const char *type;
420 const char *bin;
421 char *vpn_binary;
422 char *exit_binary;
423 int ret = 0;
424
425 if (0 != access ("/dev/net/tun", R_OK))
426 {
427 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
428 "access",
429 "/dev/net/tun");
430 fprintf (stderr,
431 "WARNING: System unable to run test, skipping.\n");
432 return 77;
433 }
434
435 vpn_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
436 exit_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-exit");
437 if ((GNUNET_YES != (ret = GNUNET_OS_check_helper_binary (vpn_binary,
438 GNUNET_YES,
439 "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")))
440 || // ipv4 only please!
441 (GNUNET_YES != (ret = GNUNET_OS_check_helper_binary (exit_binary,
442 GNUNET_YES,
443 "-d gnunet-vpn - - - 169.1.3.3.7 255.255.255.0")))) // no nat, ipv4 only
444 {
445 GNUNET_free (vpn_binary);
446 GNUNET_free (exit_binary);
447 fprintf (stderr,
448 "WARNING: gnunet-helper-{exit,vpn} binaries are not SUID, refusing to run test (as it would have to fail). %d\n",
449 ret);
450 return 77;
451 }
452
453 GNUNET_free (vpn_binary);
454 GNUNET_free (exit_binary);
455 bin = argv[0];
456 if (NULL != strstr (bin, "lt-"))
457 bin = strstr (bin, "lt-") + 4;
458 type = strstr (bin, "-");
459 if (NULL == type)
460 {
461 fprintf (stderr,
462 "invalid binary name\n");
463 return 1;
464 }
465 type++;
466 /* on Windows, .exe is suffixed to these binaries,
467 * thus cease comparison after the 6th char.
468 */
469 if (0 == strncmp (type, "4_to_6", 6))
470 {
471 dest_ip = "FC5A:04E1:C2BA::1";
472 dest_af = AF_INET6;
473 src_af = AF_INET;
474 }
475 else if (0 == strncmp (type, "6_to_4", 6))
476 {
477 dest_ip = "169.254.86.1";
478 dest_af = AF_INET;
479 src_af = AF_INET6;
480 }
481 else if (0 == strncmp (type, "4_over", 6))
482 {
483 dest_ip = "169.254.86.1";
484 dest_af = AF_INET;
485 src_af = AF_INET;
486 }
487 else if (0 == strncmp (type, "6_over", 6))
488 {
489 dest_ip = "FC5A:04E1:C2BA::1";
490 dest_af = AF_INET6;
491 src_af = AF_INET6;
492 }
493 else
494 {
495 fprintf (stderr, "invalid binary suffix `%s'\n", type);
496 return 1;
497 }
498 if ((GNUNET_OK != GNUNET_NETWORK_test_pf (src_af)) ||
499 (GNUNET_OK != GNUNET_NETWORK_test_pf (dest_af)))
500 {
501 fprintf (stderr,
502 "Required address families not supported by this system, skipping test.\n");
503 return 0;
504 }
505 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
506 {
507 fprintf (stderr, "failed to initialize curl\n");
508 return 2;
509 }
510 if (0 !=
511 GNUNET_TESTING_peer_run ("test-gnunet-vpn", "test_gnunet_vpn.conf", &run,
512 NULL))
513 return 1;
514 GNUNET_DISK_directory_remove ("/tmp/gnunet-test-vpn");
515 return global_ret;
516}
517
518
519/* end of test_gnunet_vpn.c */