2 This file is part of GNUnet
3 Copyright (C) 2007, 2009, 2011, 2012 Christian Grothoff
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file test_gns_proxy.c
23 * @brief testcase for accessing SOCKS5 GNS proxy
24 * @author Martin Schanzenbach
27 /* Just included for the right curl.h */
28 #include "gnunet_curl_lib.h"
29 #include <microhttpd.h>
30 #include "gnunet_util_lib.h"
31 #include "gnutls/x509.h"
34 * Largest allowed size for a PEM certificate.
36 #define MAX_PEM_SIZE (10 * 1024)
38 #define TEST_DOMAIN "www.test"
40 #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 300)
43 * Return value for 'main'.
45 static int global_ret;
48 static struct MHD_Daemon *mhd;
50 static struct GNUNET_SCHEDULER_Task *mhd_task_id;
52 static struct GNUNET_SCHEDULER_Task *curl_task_id;
60 static struct GNUNET_OS_Process *proxy_proc;
62 static char* cafile_opt;
64 static char* cafile_srv;
68 static gnutls_x509_crt_t proxy_cert;
70 static gnutls_x509_privkey_t proxy_key;
77 static struct CBC cbc;
80 * Read file in filename
82 * @param filename file to read
83 * @param size pointer where filesize is stored
84 * @return NULL on error
87 load_file(const char* filename,
94 GNUNET_DISK_file_size(filename,
99 if (fsize > MAX_PEM_SIZE)
101 *size = (unsigned int)fsize;
102 buffer = GNUNET_malloc(*size);
104 GNUNET_DISK_fn_read(filename,
115 * Load PEM key from file
117 * @param key where to store the data
118 * @param keyfile path to the PEM file
119 * @return #GNUNET_OK on success
122 load_key_from_file(gnutls_x509_privkey_t key,
125 gnutls_datum_t key_data;
128 key_data.data = load_file(keyfile,
130 if (NULL == key_data.data)
131 return GNUNET_SYSERR;
132 ret = gnutls_x509_privkey_import(key, &key_data,
133 GNUTLS_X509_FMT_PEM);
134 if (GNUTLS_E_SUCCESS != ret)
136 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
137 _("Unable to import private key from file `%s'\n"),
140 GNUNET_free_non_null(key_data.data);
141 return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
145 * Load cert from file
147 * @param crt struct to store data in
148 * @param certfile path to pem file
149 * @return #GNUNET_OK on success
152 load_cert_from_file(gnutls_x509_crt_t crt,
153 const char* certfile)
155 gnutls_datum_t cert_data;
158 cert_data.data = load_file(certfile,
160 if (NULL == cert_data.data)
161 return GNUNET_SYSERR;
162 ret = gnutls_x509_crt_import(crt,
164 GNUTLS_X509_FMT_PEM);
165 if (GNUTLS_E_SUCCESS != ret)
167 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
168 _("Unable to import certificate from `%s'\n"),
171 GNUNET_free_non_null(cert_data.data);
172 return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
176 copy_buffer(void *ptr, size_t size, size_t nmemb, void *ctx)
178 struct CBC *cbc = ctx;
180 if (cbc->pos + size * nmemb > sizeof(cbc->buf))
181 return 0; /* overflow */
182 GNUNET_memcpy(&cbc->buf[cbc->pos], ptr, size * nmemb);
183 cbc->pos += size * nmemb;
190 struct MHD_Connection *connection,
194 const char *upload_data, size_t *upload_data_size,
198 struct MHD_Response *response;
201 if (0 != strcmp("GET", method))
202 return MHD_NO; /* unexpected method */
209 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "MHD sends respose for request to URL `%s'\n", url);
210 response = MHD_create_response_from_buffer(strlen(url),
212 MHD_RESPMEM_MUST_COPY);
213 ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
214 MHD_destroy_response(response);
228 if (mhd_task_id != NULL)
230 GNUNET_SCHEDULER_cancel(mhd_task_id);
233 if (curl_task_id != NULL)
235 GNUNET_SCHEDULER_cancel(curl_task_id);
240 MHD_stop_daemon(mhd);
243 GNUNET_free_non_null(url);
245 if (NULL != proxy_proc)
247 (void)GNUNET_OS_process_kill(proxy_proc, SIGKILL);
248 GNUNET_assert(GNUNET_OK == GNUNET_OS_process_wait(proxy_proc));
249 GNUNET_OS_process_destroy(proxy_proc);
253 GNUNET_SCHEDULER_shutdown();
258 * Function to run the HTTP client.
279 struct GNUNET_NETWORK_FDSet nrs;
280 struct GNUNET_NETWORK_FDSet nws;
281 struct GNUNET_TIME_Relative delay;
290 curl_multi_perform(multi, &running);
293 GNUNET_assert(NULL != (msg = curl_multi_info_read(multi, &running)));
294 if (msg->msg == CURLMSG_DONE)
296 if (msg->data.result != CURLE_OK)
299 "%s failed at %s:%d: `%s'\n",
300 "curl_multi_perform",
302 __LINE__, curl_easy_strerror(msg->data.result));
306 curl_multi_remove_handle(multi, curl);
307 curl_multi_cleanup(multi);
308 curl_easy_cleanup(curl);
311 if (cbc.pos != strlen("/hello_world"))
316 if (0 != strncmp("/hello_world", cbc.buf, strlen("/hello_world")))
321 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Download complete, shutting down!\n");
325 GNUNET_assert(CURLM_OK == curl_multi_fdset(multi, &rs, &ws, &es, &max));
326 if ((CURLM_OK != curl_multi_timeout(multi, &timeout)) ||
328 delay = GNUNET_TIME_UNIT_SECONDS;
330 delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, (unsigned int)timeout);
331 GNUNET_NETWORK_fdset_copy_native(&nrs,
334 GNUNET_NETWORK_fdset_copy_native(&nws,
337 curl_task_id = GNUNET_SCHEDULER_add_select(GNUNET_SCHEDULER_PRIORITY_DEFAULT,
347 start_curl(void *cls)
350 GNUNET_asprintf(&url,
351 "https://%s:%d/hello_world",
353 curl = curl_easy_init();
354 curl_easy_setopt(curl, CURLOPT_URL, url);
355 //curl_easy_setopt (curl, CURLOPT_URL, "https://127.0.0.1:8443/hello_world");
356 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ©_buffer);
357 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &cbc);
358 curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
359 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 150L);
360 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15L);
361 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
362 curl_easy_setopt(curl, CURLOPT_CAINFO, cafile_opt);
363 //curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0L);
364 //curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0L);
365 curl_easy_setopt(curl, CURLOPT_PROXY, "socks5h://127.0.0.1:7777");
367 multi = curl_multi_init();
368 GNUNET_assert(multi != NULL);
369 GNUNET_assert(CURLM_OK == curl_multi_add_handle(multi, curl));
370 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
371 "Beginning HTTP download from `%s'\n",
378 * Callback invoked from the namestore service once record is
382 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
383 * will match 'result_af' from the request
384 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
385 * that the VPN allocated for the redirection;
386 * traffic to this IP will now be redirected to the
387 * specified target peer; NULL on error
390 commence_testing(void *cls)
393 GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS,
400 * Function to keep the HTTP server running.
418 struct GNUNET_NETWORK_FDSet nrs;
419 struct GNUNET_NETWORK_FDSet nws;
424 unsigned MHD_LONG_LONG timeout;
425 struct GNUNET_TIME_Relative delay;
427 GNUNET_assert(NULL == mhd_task_id);
432 GNUNET_assert(MHD_YES ==
433 MHD_get_fdset(mhd, &rs, &ws, &es, &max_fd));
434 if (MHD_YES == MHD_get_timeout(mhd, &timeout))
435 delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS,
436 (unsigned int)timeout);
438 delay = GNUNET_TIME_UNIT_FOREVER_REL;
439 GNUNET_NETWORK_fdset_copy_native(&nrs,
442 GNUNET_NETWORK_fdset_copy_native(&nws,
445 mhd_task_id = GNUNET_SCHEDULER_add_select(GNUNET_SCHEDULER_PRIORITY_DEFAULT,
455 * Main function that will be run
458 * @param args remaining command-line arguments
459 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
460 * @param c configuration
466 const struct GNUNET_CONFIGURATION_Handle *c)
468 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
469 "Using `%s' as CA\n",
471 char cert[MAX_PEM_SIZE];
472 char key[MAX_PEM_SIZE];
474 size_t cert_buf_size;
476 gnutls_global_init();
477 gnutls_x509_crt_init(&proxy_cert);
478 gnutls_x509_privkey_init(&proxy_key);
481 load_cert_from_file(proxy_cert,
484 load_key_from_file(proxy_key,
487 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
488 _("Failed to load X.509 key and certificate from `%s'\n"),
490 gnutls_x509_crt_deinit(proxy_cert);
491 gnutls_x509_privkey_deinit(proxy_key);
492 gnutls_global_deinit();
495 GNUNET_SCHEDULER_add_shutdown(&do_shutdown,
497 key_buf_size = sizeof(key);
498 cert_buf_size = sizeof(cert);
499 gnutls_x509_crt_export(proxy_cert,
503 gnutls_x509_privkey_export(proxy_key,
507 mhd = MHD_start_daemon(MHD_USE_DEBUG | MHD_USE_SSL | MHD_ALLOW_SUSPEND_RESUME, port,
510 MHD_OPTION_HTTPS_MEM_KEY, key,
511 MHD_OPTION_HTTPS_MEM_CERT, cert,
513 GNUNET_assert(NULL != mhd);
516 GNUNET_SCHEDULER_add_now(&commence_testing,
521 main(int argc, char *const *argv)
523 struct GNUNET_GETOPT_CommandLineOption options[] = {
524 GNUNET_GETOPT_option_uint16('p',
527 gettext_noop("listen on specified port (default: 7777)"),
529 GNUNET_GETOPT_option_string('A',
532 gettext_noop("pem file to use as CA"),
534 GNUNET_GETOPT_option_string('S',
537 gettext_noop("pem file to use for the server"),
540 GNUNET_GETOPT_OPTION_END
543 if (0 != curl_global_init(CURL_GLOBAL_WIN32))
545 fprintf(stderr, "failed to initialize curl\n");
549 GNUNET_STRINGS_get_utf8_args(argc, argv,
552 GNUNET_log_setup("gnunet-gns-proxy-test",
555 if (GNUNET_OK != GNUNET_PROGRAM_run(argc, argv,
556 "gnunet-gns-proxy-test",
557 _("GNUnet GNS proxy test"),
561 GNUNET_free_non_null((char *)argv);
565 /* end of test_gns_proxy.c */