X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fgns%2Fgnunet-gns-proxy.c;h=3af571eba90a2e7ceb7bf18ca3a5be1d580c8b25;hb=ecfab268bb34efb1305bf5b7894db47cd916a6a7;hp=124fe806d3d3d3f866428b1498f8c2a8d7c11581;hpb=2f9bbed9ec4a4e631e585e4d2facde5a326d928c;p=oweals%2Fgnunet.git diff --git a/src/gns/gnunet-gns-proxy.c b/src/gns/gnunet-gns-proxy.c index 124fe806d..3af571eba 100644 --- a/src/gns/gnunet-gns-proxy.c +++ b/src/gns/gnunet-gns-proxy.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2012-2014 Christian Grothoff (and other contributing authors) + Copyright (C) 2012-2014 GNUnet e.V. GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -48,8 +48,6 @@ #include "gns.h" -#define GNUID_HTTP_HEADER_GNUID_RESPONSE "X-GNUid-Requested-Info" - /** * Default Socks5 listen port. */ @@ -123,10 +121,6 @@ */ #define SOCKS_AUTH_NONE 0 -/** - * Enable GNUid functionality - */ -#define GNUID_ENABLED 1 /** * Commands in Socks5. @@ -366,7 +360,7 @@ struct MhdHttpList /** * The task ID */ - struct GNUNET_SCHEDULER_Task * httpd_task; + struct GNUNET_SCHEDULER_Task *httpd_task; /** * is this an ssl daemon? @@ -415,7 +409,7 @@ enum SocksPhase SOCKS5_SOCKET_WITH_MHD, /** - * We've finished receiving upload data from MHD. + * We've started receiving upload data from MHD. */ SOCKS5_SOCKET_UPLOAD_STARTED, @@ -436,6 +430,31 @@ enum SocksPhase }; +/** + * A header list + */ +struct HttpResponseHeader +{ + /** + * DLL + */ + struct HttpResponseHeader *next; + + /** + * DLL + */ + struct HttpResponseHeader *prev; + + /** + * Header type + */ + char *type; + + /** + * Header value + */ + char *value; +}; /** * A structure for socks requests @@ -538,16 +557,6 @@ struct Socks5Request */ struct curl_slist *hosts; - /** - * Custom response headers - */ - struct curl_slist *resp_headers; - - /** - * GNUid redirect - */ - char* redirect_gnuid; - /** * HTTP response code to give to MHD for the response. */ @@ -588,6 +597,20 @@ struct Socks5Request */ uint16_t port; + /** + * Headers from response + */ + struct HttpResponseHeader *header_head; + + /** + * Headers from response + */ + struct HttpResponseHeader *header_tail; + + /** + * SSL Certificate status + */ + int ssl_checked; }; @@ -598,7 +621,7 @@ struct Socks5Request /** * The port the proxy is running on (default 7777) */ -static unsigned long port = GNUNET_GNS_PROXY_PORT; +static unsigned long long port = GNUNET_GNS_PROXY_PORT; /** * The CA file (pem) to use for the proxy CA @@ -671,16 +694,6 @@ static struct Socks5Request *s5r_tail; */ static struct GNUNET_CRYPTO_EcdsaPublicKey local_gns_zone; -/** - * The users local shorten zone - */ -static struct GNUNET_CRYPTO_EcdsaPrivateKey local_shorten_zone; - -/** - * Is shortening enabled? - */ -static int do_shorten; - /** * The CA for SSL certificate generation */ @@ -739,9 +752,9 @@ cleanup_s5r (struct Socks5Request *s5r) } curl_slist_free_all (s5r->headers); if (NULL != s5r->hosts) + { curl_slist_free_all (s5r->hosts); - if (NULL != s5r->resp_headers) - curl_slist_free_all (s5r->resp_headers); + } if ( (NULL != s5r->response) && (curl_failure_response != s5r->response) ) MHD_destroy_response (s5r->response); @@ -773,6 +786,8 @@ cleanup_s5r (struct Socks5Request *s5r) /* ************************* HTTP handling with cURL *********************** */ +static void +curl_download_prepare (); /** * Callback for MHD response generation. This function is called from @@ -811,6 +826,11 @@ mhd_content_cb (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Pausing MHD download, no data available\n"); + if (NULL != s5r->curl) + { + curl_easy_pause (s5r->curl, CURLPAUSE_CONT); + curl_download_prepare (); + } return 0; /* more data later */ } if ( (0 == bytes_to_copy) && @@ -820,7 +840,9 @@ mhd_content_cb (void *cls, "Completed MHD download\n"); return MHD_CONTENT_READER_END_OF_STREAM; } - memcpy (buf, s5r->io_buf, bytes_to_copy); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Writing %lu/%lu bytes\n", bytes_to_copy, s5r->io_len); + GNUNET_memcpy (buf, s5r->io_buf, bytes_to_copy); memmove (s5r->io_buf, &s5r->io_buf[bytes_to_copy], s5r->io_len - bytes_to_copy); @@ -851,6 +873,9 @@ check_ssl_certificate (struct Socks5Request *s5r) int rc; const char *name; + s5r->ssl_checked = GNUNET_YES; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Checking SSL certificate\n"); if (CURLE_OK != curl_easy_getinfo (s5r->curl, CURLINFO_TLS_SESSION, @@ -1002,12 +1027,12 @@ static size_t curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) { struct Socks5Request *s5r = cls; + struct HttpResponseHeader *header; size_t bytes = size * nmemb; char *ndup; const char *hdr_type; const char *cookie_domain; char *hdr_val; - long resp_code; char *new_cookie_hdr; char *new_location; size_t offset; @@ -1015,48 +1040,12 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) int domain_matched; char *tok; - if (NULL == s5r->response) + /* first, check SSL certificate */ + if ((GNUNET_YES != s5r->ssl_checked) && + (HTTPS_PORT == s5r->port)) { - /* first, check SSL certificate */ - if ( (HTTPS_PORT == s5r->port) && - (GNUNET_OK != check_ssl_certificate (s5r)) ) - return 0; - - GNUNET_break (CURLE_OK == - curl_easy_getinfo (s5r->curl, - CURLINFO_RESPONSE_CODE, - &resp_code)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating MHD response with code %d\n", - (int) resp_code); - s5r->response_code = resp_code; - s5r->response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, - IO_BUFFERSIZE, - &mhd_content_cb, - s5r, - NULL); - if (NULL != s5r->leho) - { - char *cors_hdr; - - GNUNET_asprintf (&cors_hdr, - (HTTPS_PORT == s5r->port) - ? "https://%s" - : "http://%s", - s5r->leho); - - GNUNET_break (MHD_YES == - MHD_add_response_header (s5r->response, - MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, - cors_hdr)); - GNUNET_free (cors_hdr); - } - /* force connection to be closed after each request, as we - do not support HTTP pipelining (yet, FIXME!) */ - GNUNET_break (MHD_YES == - MHD_add_response_header (s5r->response, - MHD_HTTP_HEADER_CONNECTION, - "close")); + if (GNUNET_OK != check_ssl_certificate (s5r)) + return 0; } ndup = GNUNET_strndup (buffer, bytes); @@ -1079,43 +1068,43 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) new_cookie_hdr = NULL; if ( (NULL != s5r->leho) && (0 == strcasecmp (hdr_type, - MHD_HTTP_HEADER_SET_COOKIE)) ) + MHD_HTTP_HEADER_SET_COOKIE)) ) { new_cookie_hdr = GNUNET_malloc (strlen (hdr_val) + - strlen (s5r->domain) + 1); + strlen (s5r->domain) + 1); offset = 0; domain_matched = GNUNET_NO; /* make sure we match domain at most once */ for (tok = strtok (hdr_val, ";"); NULL != tok; tok = strtok (NULL, ";")) { if ( (0 == strncasecmp (tok, " domain", strlen (" domain"))) && - (GNUNET_NO == domain_matched) ) + (GNUNET_NO == domain_matched) ) { - domain_matched = GNUNET_YES; + domain_matched = GNUNET_YES; cookie_domain = tok + strlen (" domain") + 1; if (strlen (cookie_domain) < strlen (s5r->leho)) { delta_cdomain = strlen (s5r->leho) - strlen (cookie_domain); if (0 == strcasecmp (cookie_domain, s5r->leho + delta_cdomain)) - { + { offset += sprintf (new_cookie_hdr + offset, - " domain=%s;", - s5r->domain); + " domain=%s;", + s5r->domain); continue; } } else if (0 == strcmp (cookie_domain, s5r->leho)) { - offset += sprintf (new_cookie_hdr + offset, - " domain=%s;", - s5r->domain); - continue; + offset += sprintf (new_cookie_hdr + offset, + " domain=%s;", + s5r->domain); + continue; } GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Cookie domain `%s' supplied by server is invalid\n"), - tok); + tok); } - memcpy (new_cookie_hdr + offset, tok, strlen (tok)); + GNUNET_memcpy (new_cookie_hdr + offset, tok, strlen (tok)); offset += strlen (tok); new_cookie_hdr[offset++] = ';'; } @@ -1128,27 +1117,25 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) char *leho_host; GNUNET_asprintf (&leho_host, - (HTTPS_PORT != s5r->port) - ? "http://%s" - : "https://%s", - s5r->leho); + (HTTPS_PORT != s5r->port) + ? "http://%s" + : "https://%s", + s5r->leho); if (0 == strncmp (leho_host, - hdr_val, - strlen (leho_host))) + hdr_val, + strlen (leho_host))) { GNUNET_asprintf (&new_location, - "%s%s%s", - (HTTPS_PORT != s5r->port) - ? "http://" - : "https://", - s5r->domain, - hdr_val + strlen (leho_host)); + "%s%s%s", + (HTTPS_PORT != s5r->port) + ? "http://" + : "https://", + s5r->domain, + hdr_val + strlen (leho_host)); hdr_val = new_location; } GNUNET_free (leho_host); } - - /* MHD does not allow certain characters in values, remove those */ if (NULL != (tok = strchr (hdr_val, '\n'))) *tok = '\0'; @@ -1156,37 +1143,18 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) *tok = '\0'; if (NULL != (tok = strchr (hdr_val, '\t'))) *tok = '\0'; - if (GNUID_ENABLED) - { - if (0 == strcasecmp (GNUID_HTTP_HEADER_GNUID_RESPONSE, hdr_type)) - { - char* redirect; - GNUNET_asprintf (&redirect, - "%s?requested_by=http://%s:%d%s&requested_infos=%s", - "http://localhost:8000#/identities", //TODO read this from config - s5r->domain, - s5r->port, - s5r->url, - hdr_val); - - s5r->response_code = MHD_HTTP_FOUND; - GNUNET_break (MHD_YES == MHD_add_response_header (s5r->response, - MHD_HTTP_HEADER_LOCATION, - redirect)); - printf ("%s", redirect); - GNUNET_free (redirect); - } - } - if (0 != strlen (hdr_val)) + if (0 != strlen (hdr_val)) /* Rely in MHD to set those */ { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Adding header %s: %s to MHD response\n", - hdr_type, - hdr_val); - GNUNET_break (MHD_YES == - MHD_add_response_header (s5r->response, - hdr_type, - hdr_val)); + "Adding header %s: %s to MHD response\n", + hdr_type, + hdr_val); + header = GNUNET_new (struct HttpResponseHeader); + header->type = GNUNET_strndup (hdr_type, strlen (hdr_type)); + header->value = GNUNET_strndup (hdr_val, strlen (hdr_val)); + GNUNET_CONTAINER_DLL_insert (s5r->header_head, + s5r->header_tail, + header); } GNUNET_free (ndup); GNUNET_free_non_null (new_cookie_hdr); @@ -1194,6 +1162,69 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) return bytes; } +static int +create_mhd_response_from_s5r (struct Socks5Request *s5r) +{ + long resp_code; + double content_length; + struct HttpResponseHeader *header; + + if (NULL != s5r->response) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Response already set!\n"); + return GNUNET_SYSERR; + } + + GNUNET_break (CURLE_OK == + curl_easy_getinfo (s5r->curl, + CURLINFO_RESPONSE_CODE, + &resp_code)); + GNUNET_break (CURLE_OK == + curl_easy_getinfo (s5r->curl, + CURLINFO_CONTENT_LENGTH_DOWNLOAD, + &content_length)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating MHD response with code %d and size %d\n", + (int) resp_code, (int) content_length); + s5r->response_code = resp_code; + s5r->response = MHD_create_response_from_callback ((-1 == content_length) ? MHD_SIZE_UNKNOWN : content_length, + IO_BUFFERSIZE, + &mhd_content_cb, + s5r, + NULL); + for (header = s5r->header_head; NULL != header; header = header->next) + { + GNUNET_break (MHD_YES == + MHD_add_response_header (s5r->response, + header->type, + header->value)); + + } + if (NULL != s5r->leho) + { + char *cors_hdr; + + GNUNET_asprintf (&cors_hdr, + (HTTPS_PORT == s5r->port) + ? "https://%s" + : "http://%s", + s5r->leho); + + GNUNET_break (MHD_YES == + MHD_add_response_header (s5r->response, + MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, + cors_hdr)); + GNUNET_free (cors_hdr); + } + /* force connection to be closed after each request, as we + do not support HTTP pipelining (yet, FIXME!) */ + /*GNUNET_break (MHD_YES == + MHD_add_response_header (s5r->response, + MHD_HTTP_HEADER_CONNECTION, + "close"));*/ + return GNUNET_OK; +} /** * Handle response payload data from cURL. Copies it into our `io_buf` to make @@ -1211,6 +1242,9 @@ curl_download_cb (void *ptr, size_t size, size_t nmemb, void* ctx) struct Socks5Request *s5r = ctx; size_t total = size * nmemb; + if (NULL == s5r->response) + GNUNET_assert (GNUNET_OK == create_mhd_response_from_s5r (s5r)); + if ( (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) || (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) ) { @@ -1218,18 +1252,19 @@ curl_download_cb (void *ptr, size_t size, size_t nmemb, void* ctx) start the download, the IO buffer is still full with upload data. */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Pausing CURL download, waiting for UPLOAD to finish\n"); + "Pausing CURL download, waiting for UPLOAD to finish\n"); return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */ } if (sizeof (s5r->io_buf) - s5r->io_len < total) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Pausing CURL download, not enough space\n"); + "Pausing CURL download, not enough space %lu %lu %lu\n", sizeof (s5r->io_buf), + s5r->io_len, total); return CURL_WRITEFUNC_PAUSE; /* not enough space */ } - memcpy (&s5r->io_buf[s5r->io_len], - ptr, - total); + GNUNET_memcpy (&s5r->io_buf[s5r->io_len], + ptr, + total); s5r->io_len += total; if (s5r->io_len == total) run_mhd_now (s5r->hd); @@ -1258,7 +1293,7 @@ curl_upload_cb (void *buf, size_t size, size_t nmemb, void *cls) (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state) ) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Pausing CURL UPLOAD, need more data\n"); + "Pausing CURL UPLOAD, need more data\n"); return CURL_READFUNC_PAUSE; } if ( (0 == s5r->io_len) && @@ -1266,21 +1301,21 @@ curl_upload_cb (void *buf, size_t size, size_t nmemb, void *cls) { s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Completed CURL UPLOAD\n"); + "Completed CURL UPLOAD\n"); return 0; /* upload finished, can now download */ } - if ( (SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) || + if ( (SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) && (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state) ) { GNUNET_break (0); return CURL_READFUNC_ABORT; } to_copy = GNUNET_MIN (s5r->io_len, - len); - memcpy (buf, s5r->io_buf, to_copy); + len); + GNUNET_memcpy (buf, s5r->io_buf, to_copy); memmove (s5r->io_buf, - &s5r->io_buf[to_copy], - s5r->io_len - to_copy); + &s5r->io_buf[to_copy], + s5r->io_len - to_copy); s5r->io_len -= to_copy; if (s5r->io_len + to_copy == sizeof (s5r->io_buf)) run_mhd_now (s5r->hd); /* got more space for upload now */ @@ -1296,10 +1331,9 @@ curl_upload_cb (void *buf, size_t size, size_t nmemb, void *cls) * from curl * * @param cls closure - * @param tc task context */ static void -curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); +curl_task_download (void *cls); /** @@ -1348,9 +1382,9 @@ curl_download_prepare () GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); curl_download_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - rtime, - grs, gws, - &curl_task_download, curl_multi); + rtime, + grs, gws, + &curl_task_download, curl_multi); GNUNET_NETWORK_fdset_destroy (gws); GNUNET_NETWORK_fdset_destroy (grs); } @@ -1367,11 +1401,9 @@ curl_download_prepare () * Task that is run when we are ready to receive more data from curl. * * @param cls closure, NULL - * @param tc task context */ static void -curl_task_download (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +curl_task_download (void *cls) { int running; int msgnum; @@ -1387,67 +1419,64 @@ curl_task_download (void *cls, while (NULL != (msg = curl_multi_info_read (curl_multi, &msgnum))) { GNUNET_break (CURLE_OK == - curl_easy_getinfo (msg->easy_handle, - CURLINFO_PRIVATE, - (char **) &s5r )); + curl_easy_getinfo (msg->easy_handle, + CURLINFO_PRIVATE, + (char **) &s5r )); if (NULL == s5r) { - GNUNET_break (0); - continue; + GNUNET_break (0); + continue; } switch (msg->msg) { - case CURLMSG_NONE: - /* documentation says this is not used */ - GNUNET_break (0); - break; - case CURLMSG_DONE: - switch (msg->data.result) - { - case CURLE_OK: - case CURLE_GOT_NOTHING: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "CURL download completed.\n"); - s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE; - run_mhd_now (s5r->hd); - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Download curl failed: %s\n", - curl_easy_strerror (msg->data.result)); - /* FIXME: indicate error somehow? close MHD connection badly as well? */ - s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE; - run_mhd_now (s5r->hd); - break; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Cleaning up cURL handle\n"); - curl_multi_remove_handle (curl_multi, s5r->curl); - curl_easy_cleanup (s5r->curl); - s5r->curl = NULL; - if (NULL == s5r->response) - s5r->response = curl_failure_response; - break; - case CURLMSG_LAST: - /* documentation says this is not used */ - GNUNET_break (0); - break; - default: - /* unexpected status code */ - GNUNET_break (0); - break; + case CURLMSG_NONE: + /* documentation says this is not used */ + GNUNET_break (0); + break; + case CURLMSG_DONE: + switch (msg->data.result) + { + case CURLE_OK: + case CURLE_GOT_NOTHING: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL download completed.\n"); + if (NULL == s5r->response) + GNUNET_assert (GNUNET_OK == create_mhd_response_from_s5r (s5r)); + s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE; + run_mhd_now (s5r->hd); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Download curl failed: %s\n", + curl_easy_strerror (msg->data.result)); + /* FIXME: indicate error somehow? close MHD connection badly as well? */ + s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE; + run_mhd_now (s5r->hd); + break; + } + if (NULL == s5r->response) + s5r->response = curl_failure_response; + break; + case CURLMSG_LAST: + /* documentation says this is not used */ + GNUNET_break (0); + break; + default: + /* unexpected status code */ + GNUNET_break (0); + break; } }; } while (mret == CURLM_CALL_MULTI_PERFORM); if (CURLM_OK != mret) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%s failed at %s:%d: `%s'\n", + "%s failed at %s:%d: `%s'\n", "curl_multi_perform", __FILE__, __LINE__, curl_multi_strerror (mret)); if (0 == running) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Suspending cURL multi loop, no more events pending\n"); + "Suspending cURL multi loop, no more events pending\n"); return; /* nothing more in progress */ } curl_download_prepare (); @@ -1482,53 +1511,24 @@ con_val_iter (void *cls, if ( (0 == strcasecmp (MHD_HTTP_HEADER_HOST, key)) && (NULL != s5r->leho) ) value = s5r->leho; - if (0 == strcasecmp (MHD_HTTP_HEADER_CONNECTION, key)) - value = "Close"; + if (0 == strcasecmp (MHD_HTTP_HEADER_CONTENT_LENGTH, key)) + return MHD_YES; + if (0 == strcasecmp (MHD_HTTP_HEADER_ACCEPT_ENCODING, key)) + return MHD_YES; GNUNET_asprintf (&hdr, - "%s: %s", - key, - value); + "%s: %s", + key, + value); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Adding HEADER `%s' to HTTP request\n", - hdr); + "Adding HEADER `%s' to HTTP request\n", + hdr); s5r->headers = curl_slist_append (s5r->headers, - hdr); + hdr); GNUNET_free (hdr); return MHD_YES; } -/** - * Read HTTP request uri from the request. - * - * @param cls our `struct Socks5Request` - * @param kind value kind - * @param key field key - * @param value field value - * @return MHD_YES to continue to iterate - */ -static int -con_val_uri_iter (void *cls, - enum MHD_ValueKind kind, - const char *key, - const char *value) -{ - struct Socks5Request *s5r = cls; - char *hdr; - - if (0 == strcasecmp ("gnuid_token", key)) - { - GNUNET_asprintf (&hdr, - "%s: Bearer %s", - MHD_HTTP_HEADER_AUTHORIZATION, - value); - s5r->headers = curl_slist_append (s5r->headers, - hdr); - GNUNET_free (hdr); - } - return MHD_YES; -} - /** * Main MHD callback for handling requests. * @@ -1565,7 +1565,6 @@ create_response (void *cls, struct Socks5Request *s5r = *con_cls; char *curlurl; char *curl_hosts; - char *curl_headers; char ipstring[INET6_ADDRSTRLEN]; char ipaddr[INET6_ADDRSTRLEN + 2]; const struct sockaddr *sa; @@ -1579,8 +1578,8 @@ create_response (void *cls, GNUNET_break (0); return MHD_NO; } - if ( (NULL == s5r->curl) && - (SOCKS5_SOCKET_WITH_MHD == s5r->state) ) + //Fresh connection. + if (SOCKS5_SOCKET_WITH_MHD == s5r->state) { /* first time here, initialize curl handle */ sa = (const struct sockaddr *) &s5r->destination_address; @@ -1614,7 +1613,7 @@ create_response (void *cls, } GNUNET_snprintf (ipaddr, sizeof (ipaddr), - "[%s]", + "%s", ipstring); port = ntohs (s6->sin6_port); break; @@ -1622,7 +1621,8 @@ create_response (void *cls, GNUNET_break (0); return MHD_NO; } - s5r->curl = curl_easy_init (); + if (NULL == s5r->curl) + s5r->curl = curl_easy_init (); if (NULL == s5r->curl) return MHD_queue_response (con, MHD_HTTP_INTERNAL_SERVER_ERROR, @@ -1639,7 +1639,6 @@ create_response (void *cls, curl_easy_setopt (s5r->curl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt (s5r->curl, CURLOPT_PRIVATE, s5r); curl_easy_setopt (s5r->curl, CURLOPT_VERBOSE, 0); - /** * Pre-populate cache to resolve Hostname. * This is necessary as the DNS name in the CURLOPT_URL is used @@ -1669,7 +1668,6 @@ create_response (void *cls, CURLOPT_URL, curlurl); GNUNET_free (curlurl); - if (0 == strcasecmp (meth, MHD_HTTP_METHOD_PUT)) { s5r->state = SOCKS5_SOCKET_UPLOAD_STARTED; @@ -1682,8 +1680,8 @@ create_response (void *cls, else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_POST)) { s5r->state = SOCKS5_SOCKET_UPLOAD_STARTED; - curl_easy_setopt (s5r->curl, CURLOPT_POST, 1); - curl_easy_setopt (s5r->curl, CURLOPT_WRITEFUNCTION, &curl_download_cb); + curl_easy_setopt (s5r->curl, CURLOPT_POST, 1L); + curl_easy_setopt (s5r->curl, CURLOPT_WRITEFUNCTION, &curl_download_cb); curl_easy_setopt (s5r->curl, CURLOPT_WRITEDATA, s5r); curl_easy_setopt (s5r->curl, CURLOPT_READFUNCTION, &curl_upload_cb); curl_easy_setopt (s5r->curl, CURLOPT_READDATA, s5r); @@ -1693,25 +1691,17 @@ create_response (void *cls, s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED; curl_easy_setopt (s5r->curl, CURLOPT_NOBODY, 1); } - else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_GET)) + else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_OPTIONS)) { s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED; - curl_easy_setopt (s5r->curl, CURLOPT_HTTPGET, 1); - curl_easy_setopt (s5r->curl, CURLOPT_WRITEFUNCTION, &curl_download_cb); - curl_easy_setopt (s5r->curl, CURLOPT_WRITEDATA, s5r); + curl_easy_setopt (s5r->curl, CURLOPT_CUSTOMREQUEST, "OPTIONS"); } - else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_OPTIONS)) + else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_GET)) { s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED; - curl_easy_setopt (s5r->curl, CURLOPT_CUSTOMREQUEST, "OPTIONS"); + curl_easy_setopt (s5r->curl, CURLOPT_HTTPGET, 1); curl_easy_setopt (s5r->curl, CURLOPT_WRITEFUNCTION, &curl_download_cb); curl_easy_setopt (s5r->curl, CURLOPT_WRITEDATA, s5r); - GNUNET_asprintf (&curl_headers, - "%s: %s", - "Connection", - "keep-alive"); - s5r->headers = curl_slist_append(s5r->headers, curl_headers); - GNUNET_free (curl_headers); } else { @@ -1739,7 +1729,10 @@ create_response (void *cls, if (HTTPS_PORT == s5r->port) { curl_easy_setopt (s5r->curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); - curl_easy_setopt (s5r->curl, CURLOPT_SSL_VERIFYPEER, 1L); + if (NULL != s5r->dane_data) + curl_easy_setopt (s5r->curl, CURLOPT_SSL_VERIFYPEER, 0L); + else + curl_easy_setopt (s5r->curl, CURLOPT_SSL_VERIFYPEER, 1L); /* Disable cURL checking the hostname, as we will check ourselves as only we have the domain name or the LEHO or the DANE record */ curl_easy_setopt (s5r->curl, CURLOPT_SSL_VERIFYHOST, 0L); @@ -1759,19 +1752,6 @@ create_response (void *cls, MHD_get_connection_values (con, MHD_HEADER_KIND, &con_val_iter, s5r); - if (GNUID_ENABLED) - { - MHD_get_connection_values (con, - MHD_GET_ARGUMENT_KIND, - &con_val_uri_iter, s5r); - GNUNET_asprintf (&curl_headers, - "%s: %s", - "X-GNUid-Available", - "YES"); - s5r->headers = curl_slist_append(s5r->headers, curl_headers); - GNUNET_free (curl_headers); - } - curl_easy_setopt (s5r->curl, CURLOPT_HTTPHEADER, s5r->headers); curl_download_prepare (); return MHD_YES; @@ -1780,16 +1760,25 @@ create_response (void *cls, /* continuing to process request */ if (0 != *upload_data_size) { + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Processing %u bytes UPLOAD\n", + (unsigned int) *upload_data_size); + + /* FIXME: This must be set or a header with Transfer-Encoding: chunked. Else + * upload callback is not called! + */ + curl_easy_setopt (s5r->curl, CURLOPT_POSTFIELDSIZE, *upload_data_size); + left = GNUNET_MIN (*upload_data_size, sizeof (s5r->io_buf) - s5r->io_len); - memcpy (&s5r->io_buf[s5r->io_len], - upload_data, - left); + GNUNET_memcpy (&s5r->io_buf[s5r->io_len], + upload_data, + left); s5r->io_len += left; *upload_data_size -= left; GNUNET_assert (NULL != s5r->curl); curl_easy_pause (s5r->curl, CURLPAUSE_CONT); - curl_download_prepare (); return MHD_YES; } if (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) @@ -1799,9 +1788,10 @@ create_response (void *cls, s5r->state = SOCKS5_SOCKET_UPLOAD_DONE; } if (NULL == s5r->response) - return MHD_YES; /* too early to queue response, did not yet get headers from cURL */ + return MHD_YES; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Queueing response with MHD\n"); + run_mhd_now (s5r->hd); return MHD_queue_response (con, s5r->response_code, s5r->response); @@ -1812,7 +1802,7 @@ create_response (void *cls, /** - * Function called when MHD decides that we are done with a connection. + * Function called when MHD decides that we are done with a request. * * @param cls NULL * @param connection connection handle @@ -1827,6 +1817,7 @@ mhd_completed_cb (void *cls, enum MHD_RequestTerminationCode toe) { struct Socks5Request *s5r = *con_cls; + struct HttpResponseHeader *header; if (NULL == s5r) return; @@ -1834,12 +1825,101 @@ mhd_completed_cb (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "MHD encountered error handling request: %d\n", toe); - cleanup_s5r (s5r); - curl_download_prepare(); + if (NULL != s5r->curl) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Resetting cURL handle\n"); + curl_multi_remove_handle (curl_multi, s5r->curl); + curl_slist_free_all (s5r->headers); + s5r->headers = NULL; + curl_easy_reset (s5r->curl); + s5r->rbuf_len = 0; + s5r->wbuf_len = 0; + s5r->io_len = 0; + } + if ( (NULL != s5r->response) && + (curl_failure_response != s5r->response) ) + MHD_destroy_response (s5r->response); + for (header = s5r->header_head; header != NULL; header = s5r->header_head) + { + GNUNET_CONTAINER_DLL_remove (s5r->header_head, + s5r->header_tail, + header); + GNUNET_free (header->type); + GNUNET_free (header->value); + GNUNET_free (header); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished request for %s\n", s5r->url); + GNUNET_free (s5r->url); + s5r->state = SOCKS5_SOCKET_WITH_MHD; + s5r->url = NULL; + s5r->response = NULL; *con_cls = NULL; } +/** + * Function called when MHD connection is opened or closed. + * + * @param cls NULL + * @param connection connection handle + * @param con_cls value as set by the last call to + * the MHD_AccessHandlerCallback, should be our `struct Socks5Request *` + * @param toe connection notification type + */ +static void +mhd_connection_cb (void *cls, + struct MHD_Connection *connection, + void **con_cls, + enum MHD_ConnectionNotificationCode cnc) +{ + struct Socks5Request *s5r; + const union MHD_ConnectionInfo *ci; + int sock; + + switch (cnc) + { + case MHD_CONNECTION_NOTIFY_STARTED: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n"); + ci = MHD_get_connection_info (connection, + MHD_CONNECTION_INFO_CONNECTION_FD); + if (NULL == ci) + { + GNUNET_break (0); + return; + } + sock = ci->connect_fd; + for (s5r = s5r_head; NULL != s5r; s5r = s5r->next) + { + if (GNUNET_NETWORK_get_fd (s5r->sock) == sock) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Context set...\n"); + s5r->ssl_checked = GNUNET_NO; + *con_cls = s5r; + break; + } + } + break; + case MHD_CONNECTION_NOTIFY_CLOSED: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection closed... cleaning up\n"); + s5r = *con_cls; + if (NULL == s5r) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Connection stale!\n"); + return; + } + cleanup_s5r (s5r); + curl_download_prepare (); + *con_cls = NULL; + break; + default: + GNUNET_break (0); + } +} + /** * Function called when MHD first processes an incoming connection. * Gives us the respective URI information. @@ -1860,33 +1940,27 @@ mhd_log_callback (void *cls, { struct Socks5Request *s5r; const union MHD_ConnectionInfo *ci; - int sock; ci = MHD_get_connection_info (connection, - MHD_CONNECTION_INFO_CONNECTION_FD); + MHD_CONNECTION_INFO_SOCKET_CONTEXT); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url); if (NULL == ci) { GNUNET_break (0); return NULL; } - sock = ci->connect_fd; - for (s5r = s5r_head; NULL != s5r; s5r = s5r->next) + s5r = ci->socket_context; + if (NULL != s5r->url) { - if (GNUNET_NETWORK_get_fd (s5r->sock) == sock) - { - if (NULL != s5r->url) - { - GNUNET_break (0); - return NULL; - } - s5r->url = GNUNET_strdup (url); - GNUNET_SCHEDULER_cancel (s5r->timeout_task); - s5r->timeout_task = NULL; - return s5r; - } + GNUNET_break (0); + return NULL; } - GNUNET_break (0); - return NULL; + s5r->url = GNUNET_strdup (url); + if (NULL != s5r->timeout_task) + GNUNET_SCHEDULER_cancel (s5r->timeout_task); + s5r->timeout_task = NULL; + GNUNET_assert (s5r->state == SOCKS5_SOCKET_WITH_MHD); + return s5r; } @@ -1919,11 +1993,9 @@ kill_httpd (struct MhdHttpList *hd) * Task run whenever HTTP server is idle for too long. Kill it. * * @param cls the `struct MhdHttpList *` - * @param tc sched context */ static void -kill_httpd_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +kill_httpd_task (void *cls) { struct MhdHttpList *hd = cls; @@ -1936,11 +2008,9 @@ kill_httpd_task (void *cls, * Task run whenever HTTP server operations are pending. * * @param cls the `struct MhdHttpList *` of the daemon that is being run - * @param tc sched context */ static void -do_httpd (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc); +do_httpd (void *cls); /** @@ -2018,11 +2088,9 @@ schedule_httpd (struct MhdHttpList *hd) * Task run whenever HTTP server operations are pending. * * @param cls the `struct MhdHttpList` of the daemon that is being run - * @param tc scheduler context */ static void -do_httpd (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +do_httpd (void *cls) { struct MhdHttpList *hd = cls; @@ -2245,6 +2313,7 @@ lookup_ssl_httpd (const char* domain) &create_response, hd, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, NULL, + MHD_OPTION_NOTIFY_CONNECTION, &mhd_connection_cb, NULL, MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL, MHD_OPTION_EXTERNAL_LOGGER, &mhd_error_log_callback, NULL, MHD_OPTION_HTTPS_MEM_KEY, pgc->key, @@ -2269,11 +2338,9 @@ lookup_ssl_httpd (const char* domain) * the SOCKS5 handshake). Clean up. * * @param cls the `struct Socks5Request *` - * @param tc sched context */ static void -timeout_s5r_handshake (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +timeout_s5r_handshake (void *cls) { struct Socks5Request *s5r = cls; @@ -2343,11 +2410,9 @@ setup_data_transfer (struct Socks5Request *s5r) * Write data from buffer to socks5 client, then continue with state machine. * * @param cls the closure with the `struct Socks5Request` - * @param tc scheduler context */ static void -do_write (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +do_write (void *cls) { struct Socks5Request *s5r = cls; ssize_t len; @@ -2359,6 +2424,8 @@ do_write (void *cls, if (len <= 0) { /* write error: connection closed, shutdown, etc.; just clean up */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Write Error\n"); cleanup_s5r (s5r); return; } @@ -2494,9 +2561,9 @@ handle_gns_result (void *cls, got_ip = GNUNET_YES; in = (struct sockaddr_in *) &s5r->destination_address; in->sin_family = AF_INET; - memcpy (&in->sin_addr, - r->data, - r->data_size); + GNUNET_memcpy (&in->sin_addr, + r->data, + r->data_size); in->sin_port = htons (s5r->port); #if HAVE_SOCKADDR_IN_SIN_LEN in->sin_len = sizeof (*in); @@ -2521,9 +2588,9 @@ handle_gns_result (void *cls, got_ip = GNUNET_YES; in = (struct sockaddr_in6 *) &s5r->destination_address; in->sin6_family = AF_INET6; - memcpy (&in->sin6_addr, - r->data, - r->data_size); + GNUNET_memcpy (&in->sin6_addr, + r->data, + r->data_size); in->sin6_port = htons (s5r->port); #if HAVE_SOCKADDR_IN_SIN_LEN in->sin6_len = sizeof (*in); @@ -2555,9 +2622,9 @@ handle_gns_result (void *cls, GNUNET_free_non_null (s5r->dane_data); s5r->dane_data_len = r->data_size - sizeof (struct GNUNET_GNSRECORD_BoxRecord); s5r->dane_data = GNUNET_malloc (s5r->dane_data_len); - memcpy (s5r->dane_data, - &box[1], - s5r->dane_data_len); + GNUNET_memcpy (s5r->dane_data, + &box[1], + s5r->dane_data_len); break; } default: @@ -2600,11 +2667,9 @@ clear_from_s5r_rbuf (struct Socks5Request *s5r, * Read data from incoming Socks5 connection * * @param cls the closure with the `struct Socks5Request` - * @param tc the scheduler context */ static void -do_s5r_read (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +do_s5r_read (void *cls) { struct Socks5Request *s5r = cls; const struct Socks5ClientHelloMessage *c_hello; @@ -2612,8 +2677,10 @@ do_s5r_read (void *cls, const struct Socks5ClientRequestMessage *c_req; ssize_t rlen; size_t alen; + const struct GNUNET_SCHEDULER_TaskContext *tc; s5r->rtask = NULL; + tc = GNUNET_SCHEDULER_get_task_context (); if ( (NULL != tc->read_ready) && (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->sock)) ) { @@ -2633,7 +2700,7 @@ do_s5r_read (void *cls, s5r->sock, &do_s5r_read, s5r); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Processing %u bytes of socks data in state %d\n", + "Processing %zu bytes of socks data in state %d\n", s5r->rbuf_len, s5r->state); switch (s5r->state) @@ -2766,7 +2833,6 @@ do_s5r_read (void *cls, &local_gns_zone, GNUNET_DNSPARSER_TYPE_A, GNUNET_NO /* only cached */, - (GNUNET_YES == do_shorten) ? &local_shorten_zone : NULL, &handle_gns_result, s5r); break; @@ -2819,8 +2885,7 @@ do_s5r_read (void *cls, * @param tc the scheduler context */ static void -do_accept (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +do_accept (void *cls) { struct GNUNET_NETWORK_Handle *lsock = cls; struct GNUNET_NETWORK_Handle *s; @@ -2830,8 +2895,6 @@ do_accept (void *cls, ltask4 = NULL; else ltask6 = NULL; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; if (lsock == lsock4) ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, lsock, @@ -2867,11 +2930,9 @@ do_accept (void *cls, * Task run on shutdown * * @param cls closure - * @param tc task context */ static void -do_shutdown (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +do_shutdown (void *cls) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n"); @@ -3059,7 +3120,7 @@ run_cont () return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Proxy listens on port %u\n", + "Proxy listens on port %llu\n", port); /* start MHD daemon for HTTP */ @@ -3070,6 +3131,7 @@ run_cont () &create_response, hd, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, NULL, + MHD_OPTION_NOTIFY_CONNECTION, &mhd_connection_cb, NULL, MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL, MHD_OPTION_END); if (NULL == hd->daemon) @@ -3083,46 +3145,6 @@ run_cont () } -/** - * Method called to inform about the egos of the shorten zone of this peer. - * - * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get, - * this function is only called ONCE, and 'NULL' being passed in - * @a ego does indicate an error (i.e. name is taken or no default - * value is known). If @a ego is non-NULL and if '*ctx' - * is set in those callbacks, the value WILL be passed to a subsequent - * call to the identity callback of #GNUNET_IDENTITY_connect (if - * that one was not NULL). - * - * @param cls closure, NULL - * @param ego ego handle - * @param ctx context for application to store data for this ego - * (during the lifetime of this process, initially NULL) - * @param name name assigned by the user for this ego, - * NULL if the user just deleted the ego and it - * must thus no longer be used - */ -static void -identity_shorten_cb (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *name) -{ - id_op = NULL; - if (NULL == ego) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("No ego configured for `shorten-zone`\n")); - } - else - { - local_shorten_zone = *GNUNET_IDENTITY_ego_get_private_key (ego); - do_shorten = GNUNET_YES; - } - run_cont (); -} - - /** * Method called to inform about the egos of the master zone of this peer. * @@ -3159,10 +3181,7 @@ identity_master_cb (void *cls, } GNUNET_IDENTITY_ego_get_public_key (ego, &local_gns_zone); - id_op = GNUNET_IDENTITY_get (identity, - "gns-short", - &identity_shorten_cb, - NULL); + run_cont (); } @@ -3175,7 +3194,9 @@ identity_master_cb (void *cls, * @param c configuration */ static void -run (void *cls, char *const *args, const char *cfgfile, +run (void *cls, + char *const *args, + const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { char* cafile_cfg = NULL; @@ -3238,8 +3259,7 @@ run (void *cls, char *const *args, const char *cfgfile, "gns-proxy", &identity_master_cb, NULL); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, - &do_shutdown, NULL); + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); } @@ -3253,13 +3273,20 @@ run (void *cls, char *const *args, const char *cfgfile, int main (int argc, char *const *argv) { - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'p', "port", NULL, - gettext_noop ("listen on specified port (default: 7777)"), 1, - &GNUNET_GETOPT_set_ulong, &port}, - {'a', "authority", NULL, - gettext_noop ("pem file to use as CA"), 1, - &GNUNET_GETOPT_set_string, &cafile_opt}, + struct GNUNET_GETOPT_CommandLineOption options[] = { + + GNUNET_GETOPT_option_ulong ('p', + "port", + NULL, + gettext_noop ("listen on specified port (default: 7777)"), + &port), + + GNUNET_GETOPT_option_string ('a', + "authority", + NULL, + gettext_noop ("pem file to use as CA"), + &cafile_opt), + GNUNET_GETOPT_OPTION_END }; static const char* page = @@ -3267,22 +3294,26 @@ main (int argc, char *const *argv) "cURL fail"; int ret; - if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) + if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, + &argc, &argv)) return 2; - GNUNET_log_setup ("gnunet-gns-proxy", "WARNING", NULL); - curl_failure_response = MHD_create_response_from_buffer (strlen (page), - (void*)page, - MHD_RESPMEM_PERSISTENT); + GNUNET_log_setup ("gnunet-gns-proxy", + "WARNING", + NULL); + curl_failure_response + = MHD_create_response_from_buffer (strlen (page), + (void *) page, + MHD_RESPMEM_PERSISTENT); ret = (GNUNET_OK == - GNUNET_PROGRAM_run (argc, argv, "gnunet-gns-proxy", + GNUNET_PROGRAM_run (argc, argv, + "gnunet-gns-proxy", _("GNUnet GNS proxy"), options, &run, NULL)) ? 0 : 1; MHD_destroy_response (curl_failure_response); GNUNET_free_non_null ((char *) argv); - GNUNET_CRYPTO_ecdsa_key_clear (&local_shorten_zone); return ret; }