GNUnet  0.11.x
Data Structures | Macros | Enumerations | Functions | Variables
gnunet-gns-proxy.c File Reference

HTTP(S) proxy that rewrites URIs and fakes certificats to make GNS work with legacy browsers. More...

#include "platform.h"
#include <microhttpd.h>
#include "gnunet_curl_lib.h"
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/abstract.h>
#include <gnutls/crypto.h>
#include <regex.h>
#include "gnunet_util_lib.h"
#include "gnunet_gns_service.h"
#include "gnunet_identity_service.h"
#include "gns.h"
Include dependency graph for gnunet-gns-proxy.c:

Go to the source code of this file.

Data Structures

struct  Socks5ClientHelloMessage
 Client hello in Socks5 protocol. More...
 
struct  Socks5ServerHelloMessage
 Server hello in Socks5 protocol. More...
 
struct  Socks5ClientRequestMessage
 Client socks request in Socks5 protocol. More...
 
struct  Socks5ServerResponseMessage
 Server response to client requests in Socks5 protocol. More...
 
struct  ProxyCA
 A structure for CA cert/key. More...
 
struct  ProxyGNSCertificate
 Structure for GNS certificates. More...
 
struct  MhdHttpList
 A structure for all running Httpds. More...
 
struct  HttpResponseHeader
 A header list. More...
 
struct  Socks5Request
 A structure for socks requests. More...
 

Macros

#define GNUNET_GNS_PROXY_PORT   7777
 Default Socks5 listen port. More...
 
#define MAX_HTTP_URI_LENGTH   2048
 Maximum supported length for a URI. More...
 
#define MAX_DANES   32
 Maximum number of DANE records we support per domain name (and port and protocol). More...
 
#define IO_BUFFERSIZE   CURL_MAX_WRITE_SIZE
 Size of the buffer for the data upload / download. More...
 
#define SOCKS_BUFFERSIZE   (256 + 32)
 Size of the read/write buffers for Socks. More...
 
#define HTTP_PORT   80
 Port for plaintext HTTP. More...
 
#define HTTPS_PORT   443
 Port for HTTPS. More...
 
#define MAX_PEM_SIZE   (10 * 1024)
 Largest allowed size for a PEM certificate. More...
 
#define MHD_CACHE_TIMEOUT
 After how long do we clean up unused MHD TLS instances? More...
 
#define HTTP_HANDSHAKE_TIMEOUT
 After how long do we clean up Socks5 handles that failed to show any activity with their respective MHD instance? More...
 
#define LOG_CURL_EASY(level, fun, rc)
 Log curl error. More...
 
#define SOCKS_VERSION_5   0x05
 Which SOCKS version do we speak? More...
 
#define SOCKS_AUTH_NONE   0
 Flag to set for 'no authentication'. More...
 

Enumerations

enum  Socks5Commands { SOCKS5_CMD_TCP_STREAM = 1, SOCKS5_CMD_TCP_PORT = 2, SOCKS5_CMD_UDP_PORT = 3 }
 Commands in Socks5. More...
 
enum  Socks5AddressType { SOCKS5_AT_IPV4 = 1, SOCKS5_AT_DOMAINNAME = 3, SOCKS5_AT_IPV6 = 4 }
 Address types in Socks5. More...
 
enum  Socks5StatusCode {
  SOCKS5_STATUS_REQUEST_GRANTED = 0, SOCKS5_STATUS_GENERAL_FAILURE = 1, SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE = 2, SOCKS5_STATUS_NETWORK_UNREACHABLE = 3,
  SOCKS5_STATUS_HOST_UNREACHABLE = 4, SOCKS5_STATUS_CONNECTION_REFUSED_BY_HOST = 5, SOCKS5_STATUS_TTL_EXPIRED = 6, SOCKS5_STATUS_COMMAND_NOT_SUPPORTED = 7,
  SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED = 8
}
 Status codes in Socks5 response. More...
 
enum  SocksPhase {
  SOCKS5_INIT, SOCKS5_REQUEST, SOCKS5_RESOLVING, SOCKS5_DATA_TRANSFER,
  SOCKS5_WRITE_THEN_CLEANUP, SOCKS5_SOCKET_WITH_MHD, SOCKS5_SOCKET_UPLOAD_STARTED, SOCKS5_SOCKET_UPLOAD_DONE,
  SOCKS5_SOCKET_DOWNLOAD_STARTED, SOCKS5_SOCKET_DOWNLOAD_DONE
}
 The socks phases. More...
 

Functions

static void run_mhd_now (struct MhdHttpList *hd)
 Run MHD now, we have extra data ready for the callback. More...
 
static void cleanup_s5r (struct Socks5Request *s5r)
 Clean up s5r handles. More...
 
static void curl_download_prepare ()
 Ask cURL for the select() sets and schedule cURL operations. More...
 
static ssize_t mhd_content_cb (void *cls, uint64_t pos, char *buf, size_t max)
 Callback for MHD response generation. More...
 
static int check_ssl_certificate (struct Socks5Request *s5r)
 Check that the website has presented us with a valid X.509 certificate. More...
 
static size_t curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls)
 We're getting an HTTP response header from cURL. More...
 
static int create_mhd_response_from_s5r (struct Socks5Request *s5r)
 Create an MHD response object in s5r matching the information we got from curl. More...
 
static size_t curl_download_cb (void *ptr, size_t size, size_t nmemb, void *ctx)
 Handle response payload data from cURL. More...
 
static size_t curl_upload_cb (void *buf, size_t size, size_t nmemb, void *cls)
 cURL callback for uploaded (PUT/POST) data. More...
 
static void curl_task_download (void *cls)
 Task that is run when we are ready to receive more data from curl. More...
 
static int con_val_iter (void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
 Read HTTP request header field from the request. More...
 
static int create_response (void *cls, struct MHD_Connection *con, const char *url, const char *meth, const char *ver, const char *upload_data, size_t *upload_data_size, void **con_cls)
 Main MHD callback for handling requests. More...
 
static void mhd_completed_cb (void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe)
 Function called when MHD decides that we are done with a request. More...
 
static void mhd_connection_cb (void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_ConnectionNotificationCode cnc)
 Function called when MHD connection is opened or closed. More...
 
static void * mhd_log_callback (void *cls, const char *url, struct MHD_Connection *connection)
 Function called when MHD first processes an incoming connection. More...
 
static void kill_httpd (struct MhdHttpList *hd)
 Kill the given MHD daemon. More...
 
static void kill_httpd_task (void *cls)
 Task run whenever HTTP server is idle for too long. More...
 
static void do_httpd (void *cls)
 Task run whenever HTTP server operations are pending. More...
 
static void schedule_httpd (struct MhdHttpList *hd)
 Schedule MHD. More...
 
static void * load_file (const char *filename, unsigned int *size)
 Read file in filename. More...
 
static int load_key_from_file (gnutls_x509_privkey_t key, const char *keyfile)
 Load PEM key from file. More...
 
static int load_cert_from_file (gnutls_x509_crt_t crt, const char *certfile)
 Load cert from file. More...
 
static struct ProxyGNSCertificategenerate_gns_certificate (const char *name)
 Generate new certificate for specific name. More...
 
static void mhd_error_log_callback (void *cls, const char *fm, va_list ap)
 Function called by MHD with errors, suppresses them all. More...
 
static struct MhdHttpListlookup_ssl_httpd (const char *domain)
 Lookup (or create) an TLS MHD instance for a particular domain. More...
 
static void timeout_s5r_handshake (void *cls)
 Task run when a Socks5Request somehow fails to be associated with an MHD connection (i.e. More...
 
static void setup_data_transfer (struct Socks5Request *s5r)
 We're done with the Socks5 protocol, now we need to pass the connection data through to the final destination, either direct (if the protocol might not be HTTP), or via MHD (if the port looks like it should be HTTP). More...
 
static void do_write (void *cls)
 Write data from buffer to socks5 client, then continue with state machine. More...
 
static void signal_socks_failure (struct Socks5Request *s5r, enum Socks5StatusCode sc)
 Return a server response message indicating a failure to the client. More...
 
static void signal_socks_success (struct Socks5Request *s5r)
 Return a server response message indicating success. More...
 
static void handle_gns_result (void *cls, int tld, uint32_t rd_count, const struct GNUNET_GNSRECORD_Data *rd)
 Process GNS results for target domain. More...
 
static void clear_from_s5r_rbuf (struct Socks5Request *s5r, size_t len)
 Remove the first len bytes from the beginning of the read buffer. More...
 
static void do_s5r_read (void *cls)
 Read data from incoming Socks5 connection. More...
 
static void do_accept (void *cls)
 Accept new incoming connections. More...
 
static void do_shutdown (void *cls)
 Task run on shutdown. More...
 
static struct GNUNET_NETWORK_Handlebind_v4 ()
 Create an IPv4 listen socket bound to our port. More...
 
static struct GNUNET_NETWORK_Handlebind_v6 ()
 Create an IPv6 listen socket bound to our port. More...
 
static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
 Main function that will be run. More...
 
int main (int argc, char *const *argv)
 The main function for gnunet-gns-proxy. More...
 

Variables

static in_addr_t address
 The address to bind to. More...
 
static struct in6_addr address6
 The IPv6 address to bind to. More...
 
static uint16_t port = 7777
 The port the proxy is running on (default 7777) More...
 
static char * cafile_opt
 The CA file (pem) to use for the proxy CA. More...
 
static struct GNUNET_NETWORK_Handlelsock4
 The listen socket of the proxy for IPv4. More...
 
static struct GNUNET_NETWORK_Handlelsock6
 The listen socket of the proxy for IPv6. More...
 
static struct GNUNET_SCHEDULER_Taskltask4
 The listen task ID for IPv4. More...
 
static struct GNUNET_SCHEDULER_Taskltask6
 The listen task ID for IPv6. More...
 
static struct GNUNET_SCHEDULER_Taskcurl_download_task
 The cURL download task (curl multi API). More...
 
static CURLM * curl_multi
 The cURL multi handle. More...
 
static struct GNUNET_GNS_Handlegns_handle
 Handle to the GNS service. More...
 
static int disable_v6
 Disable IPv6. More...
 
static struct MhdHttpListmhd_httpd_head
 DLL for http/https daemons. More...
 
static struct MhdHttpListmhd_httpd_tail
 DLL for http/https daemons. More...
 
static struct MhdHttpListhttpd
 Daemon for HTTP (we have one per X.509 certificate, and then one for all HTTP connections; this is the one for HTTP, not HTTPS). More...
 
static struct Socks5Requests5r_head
 DLL of active socks requests. More...
 
static struct Socks5Requests5r_tail
 DLL of active socks requests. More...
 
static struct ProxyCA proxy_ca
 The CA for X.509 certificate generation. More...
 
static struct MHD_Response * curl_failure_response
 Response we return on cURL failures. More...
 
static const struct GNUNET_CONFIGURATION_Handlecfg
 Our configuration. More...
 

Detailed Description

HTTP(S) proxy that rewrites URIs and fakes certificats to make GNS work with legacy browsers.

Author
Martin Schanzenbach
Christian Grothoff

TODO:

Definition in file gnunet-gns-proxy.c.

Macro Definition Documentation

◆ GNUNET_GNS_PROXY_PORT

#define GNUNET_GNS_PROXY_PORT   7777

Default Socks5 listen port.

Definition at line 51 of file gnunet-gns-proxy.c.

◆ MAX_HTTP_URI_LENGTH

#define MAX_HTTP_URI_LENGTH   2048

Maximum supported length for a URI.

Should die.

Deprecated:

Definition at line 57 of file gnunet-gns-proxy.c.

◆ MAX_DANES

#define MAX_DANES   32

Maximum number of DANE records we support per domain name (and port and protocol).

Definition at line 63 of file gnunet-gns-proxy.c.

Referenced by handle_gns_result().

◆ IO_BUFFERSIZE

#define IO_BUFFERSIZE   CURL_MAX_WRITE_SIZE

Size of the buffer for the data upload / download.

Must be enough for curl, thus CURL_MAX_WRITE_SIZE is needed here (16k).

Definition at line 69 of file gnunet-gns-proxy.c.

Referenced by create_mhd_response_from_s5r().

◆ SOCKS_BUFFERSIZE

#define SOCKS_BUFFERSIZE   (256 + 32)

Size of the read/write buffers for Socks.

Uses 256 bytes for the hostname (at most), plus a few bytes overhead for the messages.

Definition at line 76 of file gnunet-gns-proxy.c.

◆ HTTP_PORT

#define HTTP_PORT   80

Port for plaintext HTTP.

Definition at line 81 of file gnunet-gns-proxy.c.

◆ HTTPS_PORT

#define HTTPS_PORT   443

Port for HTTPS.

Definition at line 86 of file gnunet-gns-proxy.c.

Referenced by do_s5r_read().

◆ MAX_PEM_SIZE

#define MAX_PEM_SIZE   (10 * 1024)

Largest allowed size for a PEM certificate.

Definition at line 91 of file gnunet-gns-proxy.c.

Referenced by load_file().

◆ MHD_CACHE_TIMEOUT

#define MHD_CACHE_TIMEOUT
Value:
#define GNUNET_TIME_UNIT_MINUTES
One minute.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition: time.c:442

After how long do we clean up unused MHD TLS instances?

Definition at line 96 of file gnunet-gns-proxy.c.

Referenced by schedule_httpd().

◆ HTTP_HANDSHAKE_TIMEOUT

#define HTTP_HANDSHAKE_TIMEOUT
Value:
#define GNUNET_TIME_UNIT_SECONDS
One second.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition: time.c:442

After how long do we clean up Socks5 handles that failed to show any activity with their respective MHD instance?

Definition at line 103 of file gnunet-gns-proxy.c.

Referenced by setup_data_transfer().

◆ LOG_CURL_EASY

#define LOG_CURL_EASY (   level,
  fun,
  rc 
)
Value:
GNUNET_log (level, \
_ ("%s failed at %s:%d: `%s'\n"), \
fun, \
__FILE__, \
__LINE__, \
curl_easy_strerror (rc))
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
#define GNUNET_log(kind,...)

Log curl error.

Parameters
levellog level
funname of curl_easy-function that gave the error
rcreturn code from curl

Definition at line 114 of file gnunet-gns-proxy.c.

◆ SOCKS_VERSION_5

#define SOCKS_VERSION_5   0x05

Which SOCKS version do we speak?

Definition at line 128 of file gnunet-gns-proxy.c.

Referenced by do_s5r_read(), signal_socks_failure(), and signal_socks_success().

◆ SOCKS_AUTH_NONE

#define SOCKS_AUTH_NONE   0

Flag to set for 'no authentication'.

Definition at line 133 of file gnunet-gns-proxy.c.

Referenced by do_s5r_read().

Enumeration Type Documentation

◆ Socks5Commands

Commands in Socks5.

Enumerator
SOCKS5_CMD_TCP_STREAM 

Establish TCP/IP stream.

SOCKS5_CMD_TCP_PORT 

Establish TCP port binding.

SOCKS5_CMD_UDP_PORT 

Establish UDP port binding.

Definition at line 139 of file gnunet-gns-proxy.c.

140 {
145 
150 
155 };
Establish TCP/IP stream.
Establish TCP port binding.
Establish UDP port binding.

◆ Socks5AddressType

Address types in Socks5.

Enumerator
SOCKS5_AT_IPV4 

IPv4 address.

SOCKS5_AT_DOMAINNAME 

IPv4 address.

SOCKS5_AT_IPV6 

IPv6 address.

Definition at line 161 of file gnunet-gns-proxy.c.

162 {
166  SOCKS5_AT_IPV4 = 1,
167 
172 
176  SOCKS5_AT_IPV6 = 4
177 };
IPv4 address.
IPv6 address.

◆ Socks5StatusCode

Status codes in Socks5 response.

Enumerator
SOCKS5_STATUS_REQUEST_GRANTED 
SOCKS5_STATUS_GENERAL_FAILURE 
SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE 
SOCKS5_STATUS_NETWORK_UNREACHABLE 
SOCKS5_STATUS_HOST_UNREACHABLE 
SOCKS5_STATUS_CONNECTION_REFUSED_BY_HOST 
SOCKS5_STATUS_TTL_EXPIRED 
SOCKS5_STATUS_COMMAND_NOT_SUPPORTED 
SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED 

Definition at line 183 of file gnunet-gns-proxy.c.

◆ SocksPhase

enum SocksPhase

The socks phases.

Enumerator
SOCKS5_INIT 

We're waiting to get the client hello.

SOCKS5_REQUEST 

We're waiting to get the initial request.

SOCKS5_RESOLVING 

We are currently resolving the destination.

SOCKS5_DATA_TRANSFER 

We're in transfer mode.

SOCKS5_WRITE_THEN_CLEANUP 

Finish writing the write buffer, then clean up.

SOCKS5_SOCKET_WITH_MHD 

Socket has been passed to MHD, do not close it anymore.

SOCKS5_SOCKET_UPLOAD_STARTED 

We've started receiving upload data from MHD.

SOCKS5_SOCKET_UPLOAD_DONE 

We've finished receiving upload data from MHD.

SOCKS5_SOCKET_DOWNLOAD_STARTED 

We've finished uploading data via CURL and can now download.

SOCKS5_SOCKET_DOWNLOAD_DONE 

We've finished receiving download data from cURL.

Definition at line 384 of file gnunet-gns-proxy.c.

385 {
389  SOCKS5_INIT,
390 
395 
400 
405 
410 
415 
420 
425 
430 
435 };
Socket has been passed to MHD, do not close it anymore.
We&#39;re waiting to get the client hello.
We&#39;re waiting to get the initial request.
We&#39;ve started receiving upload data from MHD.
We&#39;ve finished receiving upload data from MHD.
Finish writing the write buffer, then clean up.
We&#39;ve finished uploading data via CURL and can now download.
We&#39;ve finished receiving download data from cURL.
We are currently resolving the destination.
We&#39;re in transfer mode.

Function Documentation

◆ run_mhd_now()

static void run_mhd_now ( struct MhdHttpList hd)
static

Run MHD now, we have extra data ready for the callback.

Parameters
hdthe daemon to run now.

Definition at line 2589 of file gnunet-gns-proxy.c.

References do_httpd(), GNUNET_SCHEDULER_add_now(), GNUNET_SCHEDULER_cancel(), and MhdHttpList::httpd_task.

Referenced by create_response(), curl_download_cb(), curl_task_download(), and curl_upload_cb().

2590 {
2591  if (NULL != hd->httpd_task)
2594  hd);
2595 }
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1280
static void do_httpd(void *cls)
Task run whenever HTTP server operations are pending.
struct GNUNET_SCHEDULER_Task * httpd_task
The task ID.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:966
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cleanup_s5r()

static void cleanup_s5r ( struct Socks5Request s5r)
static

Clean up s5r handles.

Parameters
s5rthe handle to destroy

Definition at line 774 of file gnunet-gns-proxy.c.

References Socks5Request::con, Socks5Request::curl, curl_download_prepare(), curl_failure_response, curl_multi, Socks5Request::dane_data, Socks5Request::domain, Socks5Request::gns_lookup, GNUNET_CONTAINER_DLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_free_non_null, GNUNET_GNS_lookup_with_tld_cancel(), GNUNET_log, GNUNET_NETWORK_socket_close(), GNUNET_NETWORK_socket_free_memory_only_(), GNUNET_NO, GNUNET_SCHEDULER_cancel(), Socks5Request::headers, Socks5Request::hosts, Socks5Request::leho, Socks5Request::num_danes, Socks5Request::response, Socks5Request::rtask, Socks5Request::sock, state, Socks5Request::suspended, Socks5Request::timeout_task, Socks5Request::url, and Socks5Request::wtask.

Referenced by do_s5r_read(), do_shutdown(), do_write(), mhd_connection_cb(), setup_data_transfer(), and timeout_s5r_handshake().

775 {
777  "Cleaning up socks request\n");
778  if (NULL != s5r->curl)
779  {
781  "Cleaning up cURL handle\n");
782  curl_multi_remove_handle (curl_multi,
783  s5r->curl);
784  curl_easy_cleanup (s5r->curl);
785  s5r->curl = NULL;
786  }
787  if (s5r->suspended)
788  {
789  s5r->suspended = GNUNET_NO;
790  MHD_resume_connection (s5r->con);
791  }
792  curl_slist_free_all (s5r->headers);
793  if (NULL != s5r->hosts)
794  {
795  curl_slist_free_all (s5r->hosts);
796  }
797  if ((NULL != s5r->response) &&
799  {
800  MHD_destroy_response (s5r->response);
801  s5r->response = NULL;
802  }
803  if (NULL != s5r->rtask)
804  {
806  s5r->rtask = NULL;
807  }
808  if (NULL != s5r->timeout_task)
809  {
811  s5r->timeout_task = NULL;
812  }
813  if (NULL != s5r->wtask)
814  {
816  s5r->wtask = NULL;
817  }
818  if (NULL != s5r->gns_lookup)
819  {
821  s5r->gns_lookup = NULL;
822  }
823  if (NULL != s5r->sock)
824  {
825  if (SOCKS5_SOCKET_WITH_MHD <= s5r->state)
827  else
829  s5r->sock = NULL;
830  }
832  s5r_tail,
833  s5r);
835  GNUNET_free_non_null (s5r->leho);
836  GNUNET_free_non_null (s5r->url);
837  for (unsigned int i = 0; i < s5r->num_danes; i++)
838  GNUNET_free (s5r->dane_data[i]);
839  GNUNET_free (s5r);
840 }
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static struct Socks5Request * s5r_tail
DLL of active socks requests.
void * GNUNET_GNS_lookup_with_tld_cancel(struct GNUNET_GNS_LookupWithTldRequest *ltr)
Cancel pending lookup request.
Definition: gns_tld_api.c:329
struct GNUNET_SCHEDULER_Task * wtask
Client socket write task.
struct MHD_Connection * con
MHD connection for this request.
char * dane_data[32+1]
Payload of the DANE records encountered.
static struct MHD_Response * curl_failure_response
Response we return on cURL failures.
struct GNUNET_NETWORK_Handle * sock
The client socket.
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
void GNUNET_NETWORK_socket_free_memory_only_(struct GNUNET_NETWORK_Handle *desc)
Only free memory of a socket, keep the file descriptor untouched.
Definition: network.c:622
enum State state
current state of profiling
int suspended
Did we suspend MHD processing?
unsigned int num_danes
Number of entries used in dane_data_len and dane_data.
struct GNUNET_GNS_LookupWithTldRequest * gns_lookup
Handle to GNS lookup, during SOCKS5_RESOLVING phase.
struct curl_slist * headers
HTTP request headers for the curl request.
char * domain
the domain name to server (only important for TLS)
struct MHD_Response * response
MHD response object for this request.
struct GNUNET_SCHEDULER_Task * rtask
Client socket read task.
static struct Socks5Request * s5r_head
DLL of active socks requests.
struct GNUNET_SCHEDULER_Task * timeout_task
Timeout task.
struct curl_slist * hosts
DNS->IP mappings resolved through GNS.
char * leho
DNS Legacy Host Name as given by GNS, NULL if not given.
#define GNUNET_log(kind,...)
char * url
The URL to fetch.
static CURLM * curl_multi
The cURL multi handle.
int GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:560
#define GNUNET_free(ptr)
Wrapper around free.
CURL * curl
Handle to cURL.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:966
Here is the call graph for this function:
Here is the caller graph for this function:

◆ curl_download_prepare()

static void curl_download_prepare ( )
static

Ask cURL for the select() sets and schedule cURL operations.

Definition at line 1570 of file gnunet-gns-proxy.c.

References curl_multi, curl_task_download(), GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_NETWORK_fdset_copy_native(), GNUNET_NETWORK_fdset_create(), GNUNET_NETWORK_fdset_destroy(), GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_add_select(), GNUNET_SCHEDULER_cancel(), GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_relative_multiply(), GNUNET_TIME_UNIT_FOREVER_REL, and GNUNET_TIME_UNIT_MILLISECONDS.

Referenced by cleanup_s5r(), create_response(), curl_task_download(), mhd_completed_cb(), mhd_connection_cb(), and mhd_content_cb().

1571 {
1572  CURLMcode mret;
1573  fd_set rs;
1574  fd_set ws;
1575  fd_set es;
1576  int max;
1577  struct GNUNET_NETWORK_FDSet *grs;
1578  struct GNUNET_NETWORK_FDSet *gws;
1579  long to;
1580  struct GNUNET_TIME_Relative rtime;
1581 
1583  "Scheduling CURL interaction\n");
1584  if (NULL != curl_download_task)
1585  {
1587  curl_download_task = NULL;
1588  }
1589  max = -1;
1590  FD_ZERO (&rs);
1591  FD_ZERO (&ws);
1592  FD_ZERO (&es);
1593  if (CURLM_OK != (mret = curl_multi_fdset (curl_multi,
1594  &rs,
1595  &ws,
1596  &es,
1597  &max)))
1598  {
1600  "%s failed at %s:%d: `%s'\n",
1601  "curl_multi_fdset", __FILE__, __LINE__,
1602  curl_multi_strerror (mret));
1603  return;
1604  }
1605  to = -1;
1606  GNUNET_break (CURLM_OK ==
1607  curl_multi_timeout (curl_multi,
1608  &to));
1609  if (-1 == to)
1611  else
1613  to);
1614  if (-1 != max)
1615  {
1616  grs = GNUNET_NETWORK_fdset_create ();
1617  gws = GNUNET_NETWORK_fdset_create ();
1619  &rs,
1620  max + 1);
1622  &ws,
1623  max + 1);
1626  rtime,
1627  grs,
1628  gws,
1630  curl_multi);
1633  }
1634  else
1635  {
1638  curl_multi);
1639  }
1640 }
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
void GNUNET_NETWORK_fdset_copy_native(struct GNUNET_NETWORK_FDSet *to, const fd_set *from, int nfds)
Copy a native fd set into the GNUnet representation.
Definition: network.c:1120
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1266
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1253
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1250
collection of IO descriptors
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_select(enum GNUNET_SCHEDULER_Priority prio, struct GNUNET_TIME_Relative delay, const struct GNUNET_NETWORK_FDSet *rs, const struct GNUNET_NETWORK_FDSet *ws, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when any of the specified file descriptor set...
Definition: scheduler.c:1810
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition: time.c:442
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
static struct GNUNET_SCHEDULER_Task * curl_download_task
The cURL download task (curl multi API).
#define GNUNET_log(kind,...)
static void curl_task_download(void *cls)
Task that is run when we are ready to receive more data from curl.
Run with the default priority (normal P2P operations).
static CURLM * curl_multi
The cURL multi handle.
Time for relative time used by GNUnet, in microseconds.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:966
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mhd_content_cb()

static ssize_t mhd_content_cb ( void *  cls,
uint64_t  pos,
char *  buf,
size_t  max 
)
static

Callback for MHD response generation.

This function is called from MHD whenever MHD expects to get data back. Copies data from the io_buf, if available.

Parameters
clsclosure with our struct Socks5Request
posin buffer
bufwhere to copy data
maxavailable space in buf
Returns
number of bytes written to buf

Definition at line 861 of file gnunet-gns-proxy.c.

References Socks5Request::con, Socks5Request::curl, curl_download_prepare(), Socks5Request::curl_paused, Socks5Request::domain, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_MIN, GNUNET_NO, GNUNET_YES, Socks5Request::io_buf, Socks5Request::io_len, SOCKS5_SOCKET_DOWNLOAD_DONE, SOCKS5_SOCKET_UPLOAD_DONE, SOCKS5_SOCKET_UPLOAD_STARTED, Socks5Request::state, Socks5Request::suspended, and Socks5Request::url.

Referenced by create_mhd_response_from_s5r().

865 {
866  struct Socks5Request *s5r = cls;
867  size_t bytes_to_copy;
868 
869  if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
871  {
872  /* we're still not done with the upload, do not yet
873  start the download, the IO buffer is still full
874  with upload data. */
876  "Pausing MHD download %s%s, not yet ready for download\n",
877  s5r->domain,
878  s5r->url);
879  return 0; /* not yet ready for data download */
880  }
881  bytes_to_copy = GNUNET_MIN (max,
882  s5r->io_len);
883  if ((0 == bytes_to_copy) &&
885  {
887  "Pausing MHD download %s%s, no data available\n",
888  s5r->domain,
889  s5r->url);
890  if (NULL != s5r->curl)
891  {
893  "Continuing CURL interaction for %s%s\n",
894  s5r->domain,
895  s5r->url);
896  if (GNUNET_YES == s5r->curl_paused)
897  {
898  s5r->curl_paused = GNUNET_NO;
899  curl_easy_pause (s5r->curl,
900  CURLPAUSE_CONT);
901  }
903  }
904  if (GNUNET_NO == s5r->suspended)
905  {
906  MHD_suspend_connection (s5r->con);
907  s5r->suspended = GNUNET_YES;
908  }
909  return 0; /* more data later */
910  }
911  if ((0 == bytes_to_copy) &&
913  {
915  "Completed MHD download %s%s\n",
916  s5r->domain,
917  s5r->url);
918  return MHD_CONTENT_READER_END_OF_STREAM;
919  }
921  "Writing %llu/%llu bytes to %s%s\n",
922  (unsigned long long) bytes_to_copy,
923  (unsigned long long) s5r->io_len,
924  s5r->domain,
925  s5r->url);
927  s5r->io_buf,
928  bytes_to_copy);
929  memmove (s5r->io_buf,
930  &s5r->io_buf[bytes_to_copy],
931  s5r->io_len - bytes_to_copy);
932  s5r->io_len -= bytes_to_copy;
933  if ((NULL != s5r->curl) &&
934  (GNUNET_YES == s5r->curl_paused))
935  {
937  "Continuing CURL interaction for %s%s\n",
938  s5r->domain,
939  s5r->url);
940  s5r->curl_paused = GNUNET_NO;
941  curl_easy_pause (s5r->curl,
942  CURLPAUSE_CONT);
943  }
944  return bytes_to_copy;
945 }
struct MHD_Connection * con
MHD connection for this request.
int curl_paused
Did we pause CURL processing?
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_NO
Definition: gnunet_common.h:78
We&#39;ve started receiving upload data from MHD.
We&#39;ve finished receiving upload data from MHD.
size_t io_len
Number of bytes already in the IO buffer.
int suspended
Did we suspend MHD processing?
enum SocksPhase state
The socks state.
#define GNUNET_MIN(a, b)
Definition: gnunet_common.h:80
char * domain
the domain name to server (only important for TLS)
static char buf[2048]
static void curl_download_prepare()
Ask cURL for the select() sets and schedule cURL operations.
We&#39;ve finished receiving download data from cURL.
#define GNUNET_log(kind,...)
char io_buf[CURL_MAX_WRITE_SIZE]
Buffer we use for moving data between MHD and curl (in both directions).
#define GNUNET_YES
Definition: gnunet_common.h:77
char * url
The URL to fetch.
A structure for socks requests.
CURL * curl
Handle to cURL.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_ssl_certificate()

static int check_ssl_certificate ( struct Socks5Request s5r)
static

Check that the website has presented us with a valid X.509 certificate.

The certificate must either match the domain name or the LEHO name (or, if available, the TLSA record).

Parameters
s5rrequest to check for.
Returns
GNUNET_OK if the certificate is valid

Definition at line 957 of file gnunet-gns-proxy.c.

References _, Socks5Request::curl, Socks5Request::dane_data, Socks5Request::dane_data_len, Socks5Request::domain, GNUNET_break, GNUNET_DNSPARSER_MAX_NAME_LENGTH, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_NO, GNUNET_OK, GNUNET_SYSERR, GNUNET_YES, Socks5Request::leho, name, Socks5Request::num_danes, size, Socks5Request::ssl_checked, and verify.

Referenced by curl_check_hdr().

958 {
959  unsigned int cert_list_size;
960  const gnutls_datum_t *chainp;
961  const struct curl_tlssessioninfo *tlsinfo;
962  char certdn[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 3];
963  size_t size;
964  gnutls_x509_crt_t x509_cert;
965  int rc;
966  const char *name;
967 
968  s5r->ssl_checked = GNUNET_YES;
970  "Checking X.509 certificate\n");
971  if (CURLE_OK !=
972  curl_easy_getinfo (s5r->curl,
973  CURLINFO_TLS_SESSION,
974  &tlsinfo))
975  return GNUNET_SYSERR;
976  if (CURLSSLBACKEND_GNUTLS != tlsinfo->backend)
977  {
979  _ ("Unsupported CURL TLS backend %d\n"),
980  tlsinfo->backend);
981  return GNUNET_SYSERR;
982  }
983  chainp = gnutls_certificate_get_peers (tlsinfo->internals,
984  &cert_list_size);
985  if ((! chainp) ||
986  (0 == cert_list_size))
987  return GNUNET_SYSERR;
988 
989  size = sizeof(certdn);
990  /* initialize an X.509 certificate structure. */
991  gnutls_x509_crt_init (&x509_cert);
992  gnutls_x509_crt_import (x509_cert,
993  chainp,
994  GNUTLS_X509_FMT_DER);
995 
996  if (0 != (rc = gnutls_x509_crt_get_dn_by_oid (x509_cert,
997  GNUTLS_OID_X520_COMMON_NAME,
998  0, /* the first and only one */
999  0 /* no DER encoding */,
1000  certdn,
1001  &size)))
1002  {
1004  _ ("Failed to fetch CN from cert: %s\n"),
1005  gnutls_strerror (rc));
1006  gnutls_x509_crt_deinit (x509_cert);
1007  return GNUNET_SYSERR;
1008  }
1009  /* check for TLSA/DANE records */
1010 #if HAVE_GNUTLS_DANE
1011  if (0 != s5r->num_danes)
1012  {
1013  dane_state_t dane_state;
1014  dane_query_t dane_query;
1015  unsigned int verify;
1016 
1017  /* FIXME: add flags to gnutls to NOT read UNBOUND_ROOT_KEY_FILE here! */
1018  if (0 != (rc = dane_state_init (&dane_state,
1019 #ifdef DANE_F_IGNORE_DNSSEC
1020  DANE_F_IGNORE_DNSSEC |
1021 #endif
1022  DANE_F_IGNORE_LOCAL_RESOLVER)))
1023  {
1025  _ ("Failed to initialize DANE: %s\n"),
1026  dane_strerror (rc));
1027  gnutls_x509_crt_deinit (x509_cert);
1028  return GNUNET_SYSERR;
1029  }
1030  s5r->dane_data[s5r->num_danes] = NULL;
1031  s5r->dane_data_len[s5r->num_danes] = 0;
1032  if (0 != (rc = dane_raw_tlsa (dane_state,
1033  &dane_query,
1034  s5r->dane_data,
1035  s5r->dane_data_len,
1036  GNUNET_YES,
1037  GNUNET_NO)))
1038  {
1040  _ ("Failed to parse DANE record: %s\n"),
1041  dane_strerror (rc));
1042  dane_state_deinit (dane_state);
1043  gnutls_x509_crt_deinit (x509_cert);
1044  return GNUNET_SYSERR;
1045  }
1046  if (0 != (rc = dane_verify_crt_raw (dane_state,
1047  chainp,
1048  cert_list_size,
1049  gnutls_certificate_type_get (
1050  tlsinfo->internals),
1051  dane_query,
1052  0, 0,
1053  &verify)))
1054  {
1056  _ ("Failed to verify TLS connection using DANE: %s\n"),
1057  dane_strerror (rc));
1058  dane_query_deinit (dane_query);
1059  dane_state_deinit (dane_state);
1060  gnutls_x509_crt_deinit (x509_cert);
1061  return GNUNET_SYSERR;
1062  }
1063  if (0 != verify)
1064  {
1066  _ (
1067  "Failed DANE verification failed with GnuTLS verify status code: %u\n"),
1068  verify);
1069  dane_query_deinit (dane_query);
1070  dane_state_deinit (dane_state);
1071  gnutls_x509_crt_deinit (x509_cert);
1072  return GNUNET_SYSERR;
1073  }
1074  dane_query_deinit (dane_query);
1075  dane_state_deinit (dane_state);
1076  /* success! */
1077  }
1078  else
1079 #endif
1080  {
1081  /* try LEHO or ordinary domain name X509 verification */
1082  name = s5r->domain;
1083  if (NULL != s5r->leho)
1084  name = s5r->leho;
1085  if (NULL != name)
1086  {
1087  if (0 == (rc = gnutls_x509_crt_check_hostname (x509_cert,
1088  name)))
1089  {
1091  _ (
1092  "TLS certificate subject name (%s) does not match `%s': %d\n"),
1093  certdn,
1094  name,
1095  rc);
1096  gnutls_x509_crt_deinit (x509_cert);
1097  return GNUNET_SYSERR;
1098  }
1099  }
1100  else
1101  {
1102  /* we did not even have the domain name!? */
1103  GNUNET_break (0);
1104  return GNUNET_SYSERR;
1105  }
1106  }
1107  gnutls_x509_crt_deinit (x509_cert);
1108  return GNUNET_OK;
1109 }
char * dane_data[32+1]
Payload of the DANE records encountered.
int dane_data_len[32+1]
Number of bytes in dane_data.
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
#define GNUNET_DNSPARSER_MAX_NAME_LENGTH
Maximum length of a name in DNS.
int ssl_checked
X.509 Certificate status.
unsigned int num_danes
Number of entries used in dane_data_len and dane_data.
char * domain
the domain name to server (only important for TLS)
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
static unsigned int size
Size of the "table".
Definition: peer.c:67
char * leho
DNS Legacy Host Name as given by GNS, NULL if not given.
const char * name
#define GNUNET_log(kind,...)
#define GNUNET_YES
Definition: gnunet_common.h:77
static int verify
Verify mode.
Definition: gnunet-abd.c:127
CURL * curl
Handle to cURL.
Here is the caller graph for this function:

◆ curl_check_hdr()

static size_t curl_check_hdr ( void *  buffer,
size_t  size,
size_t  nmemb,
void *  cls 
)
static

We're getting an HTTP response header from cURL.

Convert it to the MHD response headers. Mostly copies the headers, but makes special adjustments to "Set-Cookie" and "Location" headers as those may need to be changed from the LEHO to the domain the browser expects.

Parameters
buffercurl buffer with a single line of header data; not 0-terminated!
sizecurl blocksize
nmembcurl blocknumber
clsour struct Socks5Request *
Returns
size of processed bytes

Definition at line 1125 of file gnunet-gns-proxy.c.

References _, check_ssl_certificate(), cleanup(), Socks5Request::domain, GNUNET_asprintf(), GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_free_non_null, GNUNET_log, GNUNET_malloc, GNUNET_memcpy, GNUNET_new, GNUNET_NO, GNUNET_OK, GNUNET_strdup, GNUNET_strndup, GNUNET_YES, Socks5Request::header_head, Socks5Request::header_tail, Socks5Request::is_tls, Socks5Request::leho, Socks5Request::ssl_checked, HttpResponseHeader::type, and HttpResponseHeader::value.

Referenced by create_response().

1129 {
1130  struct Socks5Request *s5r = cls;
1131  struct HttpResponseHeader *header;
1132  size_t bytes = size * nmemb;
1133  char *ndup;
1134  const char *hdr_type;
1135  const char *cookie_domain;
1136  char *hdr_val;
1137  char *new_cookie_hdr;
1138  char *new_location;
1139  size_t offset;
1140  size_t delta_cdomain;
1141  int domain_matched;
1142  char *tok;
1143 
1145  "Receiving HTTP response header from CURL\n");
1146  /* first, check TLS certificate */
1147  if ((GNUNET_YES != s5r->ssl_checked) &&
1148  (GNUNET_YES == s5r->is_tls))
1149  // (HTTPS_PORT == s5r->port))
1150  {
1151  if (GNUNET_OK != check_ssl_certificate (s5r))
1152  return 0;
1153  }
1154  ndup = GNUNET_strndup (buffer,
1155  bytes);
1156  hdr_type = strtok (ndup,
1157  ":");
1158  if (NULL == hdr_type)
1159  {
1160  GNUNET_free (ndup);
1161  return bytes;
1162  }
1163  hdr_val = strtok (NULL,
1164  "");
1165  if (NULL == hdr_val)
1166  {
1167  GNUNET_free (ndup);
1168  return bytes;
1169  }
1170  if (' ' == *hdr_val)
1171  hdr_val++;
1172 
1173  /* custom logic for certain header types */
1174  new_cookie_hdr = NULL;
1175  if ((NULL != s5r->leho) &&
1176  (0 == strcasecmp (hdr_type,
1177  MHD_HTTP_HEADER_SET_COOKIE)))
1178 
1179  {
1180  new_cookie_hdr = GNUNET_malloc (strlen (hdr_val)
1181  + strlen (s5r->domain) + 1);
1182  offset = 0;
1183  domain_matched = GNUNET_NO; /* make sure we match domain at most once */
1184  for (tok = strtok (hdr_val, ";"); NULL != tok; tok = strtok (NULL, ";"))
1185  {
1186  if ((0 == strncasecmp (tok,
1187  " domain",
1188  strlen (" domain"))) &&
1189  (GNUNET_NO == domain_matched))
1190  {
1191  domain_matched = GNUNET_YES;
1192  cookie_domain = tok + strlen (" domain") + 1;
1193  if (strlen (cookie_domain) < strlen (s5r->leho))
1194  {
1195  delta_cdomain = strlen (s5r->leho) - strlen (cookie_domain);
1196  if (0 == strcasecmp (cookie_domain,
1197  s5r->leho + delta_cdomain))
1198  {
1199  offset += sprintf (new_cookie_hdr + offset,
1200  " domain=%s;",
1201  s5r->domain);
1202  continue;
1203  }
1204  }
1205  else if (0 == strcmp (cookie_domain,
1206  s5r->leho))
1207  {
1208  offset += sprintf (new_cookie_hdr + offset,
1209  " domain=%s;",
1210  s5r->domain);
1211  continue;
1212  }
1213  else if (('.' == cookie_domain[0]) &&
1214  (0 == strcmp (&cookie_domain[1],
1215  s5r->leho)))
1216  {
1217  offset += sprintf (new_cookie_hdr + offset,
1218  " domain=.%s;",
1219  s5r->domain);
1220  continue;
1221  }
1223  _ ("Cookie domain `%s' supplied by server is invalid\n"),
1224  tok);
1225  }
1226  GNUNET_memcpy (new_cookie_hdr + offset,
1227  tok,
1228  strlen (tok));
1229  offset += strlen (tok);
1230  new_cookie_hdr[offset++] = ';';
1231  }
1232  hdr_val = new_cookie_hdr;
1233  }
1234 
1235  new_location = NULL;
1236  if (0 == strcasecmp (MHD_HTTP_HEADER_TRANSFER_ENCODING,
1237  hdr_type))
1238  {
1239  /* Ignore transfer encoding, set automatically by MHD if required */
1240  goto cleanup;
1241  }
1242  if ((0 == strcasecmp (MHD_HTTP_HEADER_LOCATION,
1243  hdr_type)))
1244  {
1245  char *leho_host;
1246 
1247  GNUNET_asprintf (&leho_host,
1248  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1249  ? "http://%s"
1250  : "https://%s",
1251  s5r->leho);
1252  if (0 == strncmp (leho_host,
1253  hdr_val,
1254  strlen (leho_host)))
1255  {
1256  GNUNET_asprintf (&new_location,
1257  "%s%s%s",
1258  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1259  ? "http://"
1260  : "https://",
1261  s5r->domain,
1262  hdr_val + strlen (leho_host));
1263  hdr_val = new_location;
1264  }
1265  GNUNET_free (leho_host);
1266  }
1267  if (0 == strcasecmp (MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
1268  hdr_type))
1269  {
1270  char *leho_host;
1271 
1272  GNUNET_asprintf (&leho_host,
1273  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1274  ? "http://%s"
1275  : "https://%s",
1276  s5r->leho);
1277  if (0 == strncmp (leho_host,
1278  hdr_val,
1279  strlen (leho_host)))
1280  {
1281  GNUNET_asprintf (&new_location,
1282  "%s%s",
1283  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1284  ? "http://"
1285  : "https://",
1286  s5r->domain);
1287  hdr_val = new_location;
1288  }
1289  GNUNET_free (leho_host);
1290  }
1291 
1292  /* MHD does not allow certain characters in values, remove those */
1293  if (NULL != (tok = strchr (hdr_val, '\n')))
1294  *tok = '\0';
1295  if (NULL != (tok = strchr (hdr_val, '\r')))
1296  *tok = '\0';
1297  if (NULL != (tok = strchr (hdr_val, '\t')))
1298  *tok = '\0';
1299  if (0 != strlen (hdr_val)) /* Rely in MHD to set those */
1300  {
1302  "Adding header %s: %s to MHD response\n",
1303  hdr_type,
1304  hdr_val);
1305  header = GNUNET_new (struct HttpResponseHeader);
1306  header->type = GNUNET_strdup (hdr_type);
1307  header->value = GNUNET_strdup (hdr_val);
1309  s5r->header_tail,
1310  header);
1311  }
1312 cleanup:
1313  GNUNET_free (ndup);
1314  GNUNET_free_non_null (new_cookie_hdr);
1315  GNUNET_free_non_null (new_location);
1316  return bytes;
1317 }
struct HttpResponseHeader * header_head
Headers from response.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
char * value
Header value.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
char * type
Header type.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
A header list.
struct HttpResponseHeader * header_tail
Headers from response.
int ssl_checked
X.509 Certificate status.
static int check_ssl_certificate(struct Socks5Request *s5r)
Check that the website has presented us with a valid X.509 certificate.
char * domain
the domain name to server (only important for TLS)
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
static unsigned int size
Size of the "table".
Definition: peer.c:67
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
char * leho
DNS Legacy Host Name as given by GNS, NULL if not given.
#define GNUNET_log(kind,...)
int is_tls
This is (probably) a TLS connection.
#define GNUNET_YES
Definition: gnunet_common.h:77
A structure for socks requests.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_mhd_response_from_s5r()

static int create_mhd_response_from_s5r ( struct Socks5Request s5r)
static

Create an MHD response object in s5r matching the information we got from curl.

Parameters
s5rthe request for which we convert the response
Returns
GNUNET_OK on success, GNUNET_SYSERR if response was already initialized before

Definition at line 1329 of file gnunet-gns-proxy.c.

References Socks5Request::con, Socks5Request::curl, Socks5Request::domain, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_log, GNUNET_NO, GNUNET_OK, GNUNET_SYSERR, Socks5Request::header_head, IO_BUFFERSIZE, mhd_content_cb(), HttpResponseHeader::next, Socks5Request::response, Socks5Request::response_code, Socks5Request::suspended, and Socks5Request::url.

Referenced by curl_download_cb(), and curl_task_download().

1330 {
1331  long resp_code;
1332  double content_length;
1333 
1334  if (NULL != s5r->response)
1335  {
1337  "Response already set!\n");
1338  return GNUNET_SYSERR;
1339  }
1340 
1341  GNUNET_break (CURLE_OK ==
1342  curl_easy_getinfo (s5r->curl,
1343  CURLINFO_RESPONSE_CODE,
1344  &resp_code));
1345  GNUNET_break (CURLE_OK ==
1346  curl_easy_getinfo (s5r->curl,
1347  CURLINFO_CONTENT_LENGTH_DOWNLOAD,
1348  &content_length));
1350  "Creating MHD response with code %d and size %d for %s%s\n",
1351  (int) resp_code,
1352  (int) content_length,
1353  s5r->domain,
1354  s5r->url);
1355  s5r->response_code = resp_code;
1356  s5r->response = MHD_create_response_from_callback ((-1 == content_length)
1357  ? MHD_SIZE_UNKNOWN
1358  : content_length,
1359  IO_BUFFERSIZE,
1360  &mhd_content_cb,
1361  s5r,
1362  NULL);
1363  for (struct HttpResponseHeader *header = s5r->header_head;
1364  NULL != header;
1365  header = header->next)
1366  {
1367  if (0 == strcasecmp (header->type,
1368  MHD_HTTP_HEADER_CONTENT_LENGTH))
1369  continue; /* MHD won't let us mess with those, for good reason */
1370  if ((0 == strcasecmp (header->type,
1371  MHD_HTTP_HEADER_TRANSFER_ENCODING)) &&
1372  ((0 == strcasecmp (header->value,
1373  "identity")) ||
1374  (0 == strcasecmp (header->value,
1375  "chunked"))))
1376  continue; /* MHD won't let us mess with those, for good reason */
1377  if (MHD_YES !=
1378  MHD_add_response_header (s5r->response,
1379  header->type,
1380  header->value))
1381  {
1382  GNUNET_break (0);
1384  "Failed to add header `%s:%s'\n",
1385  header->type,
1386  header->value);
1387  }
1388  }
1389  /* force connection to be closed after each request, as we
1390  do not support HTTP pipelining (yet, FIXME!) */
1391  /*GNUNET_break (MHD_YES ==
1392  MHD_add_response_header (s5r->response,
1393  MHD_HTTP_HEADER_CONNECTION,
1394  "close"));*/
1395  MHD_resume_connection (s5r->con);
1396  s5r->suspended = GNUNET_NO;
1397  return GNUNET_OK;
1398 }
struct HttpResponseHeader * header_head
Headers from response.
struct MHD_Connection * con
MHD connection for this request.
#define IO_BUFFERSIZE
Size of the buffer for the data upload / download.
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
struct HttpResponseHeader * next
DLL.
A header list.
int suspended
Did we suspend MHD processing?
char * domain
the domain name to server (only important for TLS)
struct MHD_Response * response
MHD response object for this request.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
static ssize_t mhd_content_cb(void *cls, uint64_t pos, char *buf, size_t max)
Callback for MHD response generation.
#define GNUNET_log(kind,...)
char * url
The URL to fetch.
unsigned int response_code
HTTP response code to give to MHD for the response.
CURL * curl
Handle to cURL.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ curl_download_cb()

static size_t curl_download_cb ( void *  ptr,
size_t  size,
size_t  nmemb,
void *  ctx 
)
static

Handle response payload data from cURL.

Copies it into our io_buf to make it available to MHD.

Parameters
ptrpointer to the data
sizenumber of blocks of data
nmembblocksize
ctxour struct Socks5Request *
Returns
number of bytes handled

Definition at line 1412 of file gnunet-gns-proxy.c.

References Socks5Request::con, create_mhd_response_from_s5r(), ctx, Socks5Request::curl_paused, Socks5Request::domain, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_NO, GNUNET_OK, GNUNET_YES, Socks5Request::hd, Socks5Request::io_buf, Socks5Request::io_len, Socks5Request::response, run_mhd_now(), SOCKS5_SOCKET_DOWNLOAD_STARTED, SOCKS5_SOCKET_UPLOAD_DONE, SOCKS5_SOCKET_UPLOAD_STARTED, Socks5Request::state, Socks5Request::suspended, and Socks5Request::url.

Referenced by create_response().

1416 {
1417  struct Socks5Request *s5r = ctx;
1418  size_t total = size * nmemb;
1419 
1421  "Receiving %ux%u bytes for `%s%s' from cURL to download\n",
1422  (unsigned int) size,
1423  (unsigned int) nmemb,
1424  s5r->domain,
1425  s5r->url);
1426  if (NULL == s5r->response)
1429  if ((SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) &&
1430  (0 == s5r->io_len))
1431  {
1433  "Previous upload finished... starting DOWNLOAD.\n");
1435  }
1436  if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
1437  (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1438  {
1439  /* we're still not done with the upload, do not yet
1440  start the download, the IO buffer is still full
1441  with upload data. */
1443  "Pausing CURL download `%s%s', waiting for UPLOAD to finish\n",
1444  s5r->domain,
1445  s5r->url);
1446  s5r->curl_paused = GNUNET_YES;
1447  return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */
1448  }
1449  if (sizeof(s5r->io_buf) - s5r->io_len < total)
1450  {
1452  "Pausing CURL `%s%s' download, not enough space %llu %llu %llu\n",
1453  s5r->domain,
1454  s5r->url,
1455  (unsigned long long) sizeof(s5r->io_buf),
1456  (unsigned long long) s5r->io_len,
1457  (unsigned long long) total);
1458  s5r->curl_paused = GNUNET_YES;
1459  return CURL_WRITEFUNC_PAUSE; /* not enough space */
1460  }
1461  GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
1462  ptr,
1463  total);
1464  s5r->io_len += total;
1465  if (GNUNET_YES == s5r->suspended)
1466  {
1467  MHD_resume_connection (s5r->con);
1468  s5r->suspended = GNUNET_NO;
1469  }
1471  "Received %llu bytes of payload via cURL from %s\n",
1472  (unsigned long long) total,
1473  s5r->domain);
1474  if (s5r->io_len == total)
1475  run_mhd_now (s5r->hd);
1476  return total;
1477 }
struct MHD_Connection * con
MHD connection for this request.
static int create_mhd_response_from_s5r(struct Socks5Request *s5r)
Create an MHD response object in s5r matching the information we got from curl.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
int curl_paused
Did we pause CURL processing?
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
We&#39;ve started receiving upload data from MHD.
We&#39;ve finished receiving upload data from MHD.
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
size_t io_len
Number of bytes already in the IO buffer.
int suspended
Did we suspend MHD processing?
enum SocksPhase state
The socks state.
struct MhdHttpList * hd
MHD HTTP instance handling this request, NULL for none.
char * domain
the domain name to server (only important for TLS)
struct MHD_Response * response
MHD response object for this request.
static unsigned int size
Size of the "table".
Definition: peer.c:67
We&#39;ve finished uploading data via CURL and can now download.
#define GNUNET_log(kind,...)
char io_buf[CURL_MAX_WRITE_SIZE]
Buffer we use for moving data between MHD and curl (in both directions).
#define GNUNET_YES
Definition: gnunet_common.h:77
char * url
The URL to fetch.
A structure for socks requests.
static void run_mhd_now(struct MhdHttpList *hd)
Run MHD now, we have extra data ready for the callback.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ curl_upload_cb()

static size_t curl_upload_cb ( void *  buf,
size_t  size,
size_t  nmemb,
void *  cls 
)
static

cURL callback for uploaded (PUT/POST) data.

Copies it into our io_buf to make it available to MHD.

Parameters
bufwhere to write the data
sizenumber of bytes per member
nmembnumber of members available in buf
clsour struct Socks5Request that generated the data
Returns
number of bytes copied to buf

Definition at line 1491 of file gnunet-gns-proxy.c.

References Socks5Request::curl, Socks5Request::curl_paused, curl_task_download(), Socks5Request::domain, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_MIN, GNUNET_NO, GNUNET_YES, Socks5Request::hd, Socks5Request::io_buf, Socks5Request::io_len, len, run_mhd_now(), SOCKS5_SOCKET_DOWNLOAD_STARTED, SOCKS5_SOCKET_UPLOAD_DONE, SOCKS5_SOCKET_UPLOAD_STARTED, Socks5Request::state, and Socks5Request::url.

Referenced by create_response().

1495 {
1496  struct Socks5Request *s5r = cls;
1497  size_t len = size * nmemb;
1498  size_t to_copy;
1499 
1501  "Receiving %ux%u bytes for `%s%s' from cURL to upload\n",
1502  (unsigned int) size,
1503  (unsigned int) nmemb,
1504  s5r->domain,
1505  s5r->url);
1506 
1507  if ((0 == s5r->io_len) &&
1508  (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1509  {
1511  "Pausing CURL UPLOAD %s%s, need more data\n",
1512  s5r->domain,
1513  s5r->url);
1514  return CURL_READFUNC_PAUSE;
1515  }
1516  if ((0 == s5r->io_len) &&
1517  (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1518  {
1520  if (GNUNET_YES == s5r->curl_paused)
1521  {
1522  s5r->curl_paused = GNUNET_NO;
1523  curl_easy_pause (s5r->curl,
1524  CURLPAUSE_CONT);
1525  }
1527  "Completed CURL UPLOAD %s%s\n",
1528  s5r->domain,
1529  s5r->url);
1530  return 0; /* upload finished, can now download */
1531  }
1532  if ((SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) &&
1533  (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1534  {
1535  GNUNET_break (0);
1536  return CURL_READFUNC_ABORT;
1537  }
1538  to_copy = GNUNET_MIN (s5r->io_len,
1539  len);
1540  GNUNET_memcpy (buf,
1541  s5r->io_buf,
1542  to_copy);
1543  memmove (s5r->io_buf,
1544  &s5r->io_buf[to_copy],
1545  s5r->io_len - to_copy);
1546  s5r->io_len -= to_copy;
1547  if (s5r->io_len + to_copy == sizeof(s5r->io_buf))
1548  run_mhd_now (s5r->hd); /* got more space for upload now */
1549  return to_copy;
1550 }
int curl_paused
Did we pause CURL processing?
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_NO
Definition: gnunet_common.h:78
We&#39;ve started receiving upload data from MHD.
We&#39;ve finished receiving upload data from MHD.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
size_t io_len
Number of bytes already in the IO buffer.
enum SocksPhase state
The socks state.
struct MhdHttpList * hd
MHD HTTP instance handling this request, NULL for none.
#define GNUNET_MIN(a, b)
Definition: gnunet_common.h:80
char * domain
the domain name to server (only important for TLS)
static char buf[2048]
static unsigned int size
Size of the "table".
Definition: peer.c:67
We&#39;ve finished uploading data via CURL and can now download.
#define GNUNET_log(kind,...)
char io_buf[CURL_MAX_WRITE_SIZE]
Buffer we use for moving data between MHD and curl (in both directions).
#define GNUNET_YES
Definition: gnunet_common.h:77
char * url
The URL to fetch.
A structure for socks requests.
static void run_mhd_now(struct MhdHttpList *hd)
Run MHD now, we have extra data ready for the callback.
CURL * curl
Handle to cURL.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
Here is the call graph for this function:
Here is the caller graph for this function:

◆ curl_task_download()

static void curl_task_download ( void *  cls)
static

Task that is run when we are ready to receive more data from curl.

Parameters
clsclosure
clsclosure, NULL

Definition at line 1649 of file gnunet-gns-proxy.c.

References create_mhd_response_from_s5r(), curl_download_prepare(), curl_failure_response, curl_multi, GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_NO, GNUNET_OK, GNUNET_SCHEDULER_cancel(), GNUNET_YES, msg, run_mhd_now(), and SOCKS5_SOCKET_DOWNLOAD_DONE.

Referenced by curl_download_prepare(), and curl_upload_cb().

1650 {
1651  int running;
1652  int msgnum;
1653  struct CURLMsg *msg;
1654  CURLMcode mret;
1655  struct Socks5Request *s5r;
1656 
1657  curl_download_task = NULL;
1659  "Running CURL interaction\n");
1660  do
1661  {
1662  running = 0;
1663  mret = curl_multi_perform (curl_multi,
1664  &running);
1666  "Checking CURL multi status: %d\n",
1667  mret);
1668  while (NULL != (msg = curl_multi_info_read (curl_multi,
1669  &msgnum)))
1670  {
1671  GNUNET_break (CURLE_OK ==
1672  curl_easy_getinfo (msg->easy_handle,
1673  CURLINFO_PRIVATE,
1674  (char **) &s5r));
1675  if (NULL == s5r)
1676  {
1677  GNUNET_break (0);
1678  continue;
1679  }
1680  switch (msg->msg)
1681  {
1682  case CURLMSG_NONE:
1683  /* documentation says this is not used */
1684  GNUNET_break (0);
1685  break;
1686 
1687  case CURLMSG_DONE:
1688  switch (msg->data.result)
1689  {
1690  case CURLE_OK:
1691  case CURLE_GOT_NOTHING:
1693  "CURL download %s%s completed.\n",
1694  s5r->domain,
1695  s5r->url);
1696  if (NULL == s5r->response)
1697  {
1700  }
1702  if (GNUNET_YES == s5r->suspended)
1703  {
1704  MHD_resume_connection (s5r->con);
1705  s5r->suspended = GNUNET_NO;
1706  }
1707  run_mhd_now (s5r->hd);
1708  break;
1709 
1710  default:
1712  "Download curl %s%s failed: %s\n",
1713  s5r->domain,
1714  s5r->url,
1715  curl_easy_strerror (msg->data.result));
1716  /* FIXME: indicate error somehow? close MHD connection badly as well? */
1718  if (GNUNET_YES == s5r->suspended)
1719  {
1720  MHD_resume_connection (s5r->con);
1721  s5r->suspended = GNUNET_NO;
1722  }
1723  run_mhd_now (s5r->hd);
1724  break;
1725  }
1726  if (NULL == s5r->response)
1728  break;
1729 
1730  case CURLMSG_LAST:
1731  /* documentation says this is not used */
1732  GNUNET_break (0);
1733  break;
1734 
1735  default:
1736  /* unexpected status code */
1737  GNUNET_break (0);
1738  break;
1739  }
1740  }
1741  ;
1742  }
1743  while (mret == CURLM_CALL_MULTI_PERFORM);
1744  if (CURLM_OK != mret)
1746  "%s failed at %s:%d: `%s'\n",
1747  "curl_multi_perform", __FILE__, __LINE__,
1748  curl_multi_strerror (mret));
1749  if (0 == running)
1750  {
1752  "Suspending cURL multi loop, no more events pending\n");
1753  if (NULL != curl_download_task)
1754  {
1756  curl_download_task = NULL;
1757  }
1758  return; /* nothing more in progress */
1759  }
1761 }
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
struct MHD_Connection * con
MHD connection for this request.
static int create_mhd_response_from_s5r(struct Socks5Request *s5r)
Create an MHD response object in s5r matching the information we got from curl.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static struct MHD_Response * curl_failure_response
Response we return on cURL failures.
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
int suspended
Did we suspend MHD processing?
enum SocksPhase state
The socks state.
struct MhdHttpList * hd
MHD HTTP instance handling this request, NULL for none.
char * domain
the domain name to server (only important for TLS)
struct MHD_Response * response
MHD response object for this request.
static struct GNUNET_SCHEDULER_Task * curl_download_task
The cURL download task (curl multi API).
static void curl_download_prepare()
Ask cURL for the select() sets and schedule cURL operations.
We&#39;ve finished receiving download data from cURL.
#define GNUNET_log(kind,...)
#define GNUNET_YES
Definition: gnunet_common.h:77
char * url
The URL to fetch.
A structure for socks requests.
static CURLM * curl_multi
The cURL multi handle.
static void run_mhd_now(struct MhdHttpList *hd)
Run MHD now, we have extra data ready for the callback.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:966
Here is the call graph for this function:
Here is the caller graph for this function:

◆ con_val_iter()

static int con_val_iter ( void *  cls,
enum MHD_ValueKind  kind,
const char *  key,
const char *  value 
)
static

Read HTTP request header field from the request.

Copies the fields over to the 'headers' that will be given to curl. However, 'Host' is substituted with the LEHO if present. We also change the 'Connection' header value to "close" as the proxy does not support pipelining.

Parameters
clsour struct Socks5Request
kindvalue kind
keyfield key
valuefield value
Returns
#MHD_YES to continue to iterate

Definition at line 1781 of file gnunet-gns-proxy.c.

References GNUNET_asprintf(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, Socks5Request::headers, and Socks5Request::leho.

Referenced by create_response().

1785 {
1786  struct Socks5Request *s5r = cls;
1787  char *hdr;
1788 
1789  if ((0 == strcasecmp (MHD_HTTP_HEADER_HOST,
1790  key)) &&
1791  (NULL != s5r->leho))
1792  value = s5r->leho;
1793  GNUNET_asprintf (&hdr,
1794  "%s: %s",
1795  key,
1796  value);
1798  "Adding HEADER `%s' to HTTP request\n",
1799  hdr);
1800  s5r->headers = curl_slist_append (s5r->headers,
1801  hdr);
1802  GNUNET_free (hdr);
1803  return MHD_YES;
1804 }
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
static char * value
Value of the record to add/remove.
struct curl_slist * headers
HTTP request headers for the curl request.
struct GNUNET_HashCode key
The key used in the DHT.
char * leho
DNS Legacy Host Name as given by GNS, NULL if not given.
#define GNUNET_log(kind,...)
A structure for socks requests.
#define GNUNET_free(ptr)
Wrapper around free.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_response()

static int create_response ( void *  cls,
struct MHD_Connection *  con,
const char *  url,
const char *  meth,
const char *  ver,
const char *  upload_data,
size_t *  upload_data_size,
void **  con_cls 
)
static

Main MHD callback for handling requests.

Parameters
clsunused
conMHD connection handle
urlthe url in the request
meththe HTTP method used ("GET", "PUT", etc.)
verthe HTTP version string (i.e. "HTTP/1.1")
upload_datathe data being uploaded (excluding HEADERS, for a POST that fits into memory and that is encoded with a supported encoding, the POST data will NOT be given in upload_data and is instead available as part of MHD_get_connection_values; very large POST data will be made available incrementally in upload_data)
upload_data_sizeset initially to the size of the upload_data provided; the method must update this value to the number of bytes NOT processed;
con_clspointer to location where we store the struct Request
Returns
#MHD_YES if the connection was handled successfully, #MHD_NO if the socket must be closed due to a serious error while handling the request

Pre-populate cache to resolve Hostname. This is necessary as the DNS name in the CURLOPT_URL is used for SNI http://de.wikipedia.org/wiki/Server_Name_Indication

Definition at line 1831 of file gnunet-gns-proxy.c.

References _, Socks5Request::con, con_val_iter(), Socks5Request::curl, curl_check_hdr(), curl_download_cb(), curl_download_prepare(), curl_failure_response, curl_multi, Socks5Request::curl_paused, curl_upload_cb(), Socks5Request::destination_address, Socks5Request::domain, GNUNET_asprintf(), GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, GNUNET_memcpy, GNUNET_MIN, GNUNET_NO, GNUNET_snprintf(), GNUNET_YES, Socks5Request::hd, Socks5Request::headers, Socks5Request::hosts, Socks5Request::io_buf, Socks5Request::io_len, Socks5Request::is_gns, Socks5Request::is_tls, Socks5Request::leho, Socks5Request::num_danes, Socks5Request::port, port, Socks5Request::response, Socks5Request::response_code, run_mhd_now(), SOCKS5_SOCKET_DOWNLOAD_STARTED, SOCKS5_SOCKET_UPLOAD_DONE, SOCKS5_SOCKET_UPLOAD_STARTED, SOCKS5_SOCKET_WITH_MHD, Socks5Request::state, Socks5Request::suspended, and Socks5Request::url.

Referenced by lookup_ssl_httpd(), and run().

1839 {
1840  struct Socks5Request *s5r = *con_cls;
1841  char *curlurl;
1842  char ipstring[INET6_ADDRSTRLEN];
1843  char ipaddr[INET6_ADDRSTRLEN + 2];
1844  const struct sockaddr *sa;
1845  const struct sockaddr_in *s4;
1846  const struct sockaddr_in6 *s6;
1847  uint16_t port;
1848  size_t left;
1849 
1850  if (NULL == s5r)
1851  {
1852  GNUNET_break (0);
1853  return MHD_NO;
1854  }
1855  s5r->con = con;
1856  /* Fresh connection. */
1857  if (SOCKS5_SOCKET_WITH_MHD == s5r->state)
1858  {
1859  /* first time here, initialize curl handle */
1860  if (s5r->is_gns)
1861  {
1862  sa = (const struct sockaddr *) &s5r->destination_address;
1863  switch (sa->sa_family)
1864  {
1865  case AF_INET:
1866  s4 = (const struct sockaddr_in *) &s5r->destination_address;
1867  if (NULL == inet_ntop (AF_INET,
1868  &s4->sin_addr,
1869  ipstring,
1870  sizeof(ipstring)))
1871  {
1872  GNUNET_break (0);
1873  return MHD_NO;
1874  }
1875  GNUNET_snprintf (ipaddr,
1876  sizeof(ipaddr),
1877  "%s",
1878  ipstring);
1879  port = ntohs (s4->sin_port);
1880  break;
1881 
1882  case AF_INET6:
1883  s6 = (const struct sockaddr_in6 *) &s5r->destination_address;
1884  if (NULL == inet_ntop (AF_INET6,
1885  &s6->sin6_addr,
1886  ipstring,
1887  sizeof(ipstring)))
1888  {
1889  GNUNET_break (0);
1890  return MHD_NO;
1891  }
1892  GNUNET_snprintf (ipaddr,
1893  sizeof(ipaddr),
1894  "%s",
1895  ipstring);
1896  port = ntohs (s6->sin6_port);
1897  break;
1898 
1899  default:
1900  GNUNET_break (0);
1901  return MHD_NO;
1902  }
1903  }
1904  else
1905  {
1906  port = s5r->port;
1907  }
1908  if (NULL == s5r->curl)
1909  s5r->curl = curl_easy_init ();
1910  if (NULL == s5r->curl)
1911  return MHD_queue_response (con,
1912  MHD_HTTP_INTERNAL_SERVER_ERROR,
1914  curl_easy_setopt (s5r->curl,
1915  CURLOPT_HEADERFUNCTION,
1916  &curl_check_hdr);
1917  curl_easy_setopt (s5r->curl,
1918  CURLOPT_HEADERDATA,
1919  s5r);
1920  curl_easy_setopt (s5r->curl,
1921  CURLOPT_FOLLOWLOCATION,
1922  0);
1923  if (s5r->is_gns)
1924  curl_easy_setopt (s5r->curl,
1925  CURLOPT_IPRESOLVE,
1926  CURL_IPRESOLVE_V4);
1927  curl_easy_setopt (s5r->curl,
1928  CURLOPT_CONNECTTIMEOUT,
1929  600L);
1930  curl_easy_setopt (s5r->curl,
1931  CURLOPT_TIMEOUT,
1932  600L);
1933  curl_easy_setopt (s5r->curl,
1934  CURLOPT_NOSIGNAL,
1935  1L);
1936  curl_easy_setopt (s5r->curl,
1937  CURLOPT_HTTP_CONTENT_DECODING,
1938  0);
1939  curl_easy_setopt (s5r->curl,
1940  CURLOPT_NOSIGNAL,
1941  1L);
1942  curl_easy_setopt (s5r->curl,
1943  CURLOPT_PRIVATE,
1944  s5r);
1945  curl_easy_setopt (s5r->curl,
1946  CURLOPT_VERBOSE,
1947  0L);if (NULL != s5r->leho)
1953  {
1954  char *curl_hosts;
1955 
1956  GNUNET_asprintf (&curl_hosts,
1957  "%s:%d:%s",
1958  s5r->leho,
1959  port,
1960  ipaddr);
1961  s5r->hosts = curl_slist_append (NULL,
1962  curl_hosts);
1963  curl_easy_setopt (s5r->curl,
1964  CURLOPT_RESOLVE,
1965  s5r->hosts);
1966  GNUNET_free (curl_hosts);
1967  }
1968  if (s5r->is_gns)
1969  {
1970  GNUNET_asprintf (&curlurl,
1971  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1972  ? "http://%s:%d%s"
1973  : "https://%s:%d%s",
1974  (NULL != s5r->leho)
1975  ? s5r->leho
1976  : ipaddr,
1977  port,
1978  s5r->url);
1979  }
1980  else
1981  {
1982  GNUNET_asprintf (&curlurl,
1983  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1984  ? "http://%s:%d%s"
1985  : "https://%s:%d%s",
1986  s5r->domain,
1987  port,
1988  s5r->url);
1989  }
1990  curl_easy_setopt (s5r->curl,
1991  CURLOPT_URL,
1992  curlurl);
1994  "Launching %s CURL interaction, fetching `%s'\n",
1995  (s5r->is_gns) ? "GNS" : "DNS",
1996  curlurl);
1997  GNUNET_free (curlurl);
1998  if (0 == strcasecmp (meth,
1999  MHD_HTTP_METHOD_PUT))
2000  {
2002  curl_easy_setopt (s5r->curl,
2003  CURLOPT_UPLOAD,
2004  1L);
2005  curl_easy_setopt (s5r->curl,
2006  CURLOPT_WRITEFUNCTION,
2007  &curl_download_cb);
2008  curl_easy_setopt (s5r->curl,
2009  CURLOPT_WRITEDATA,
2010  s5r);
2011  GNUNET_assert (CURLE_OK ==
2012  curl_easy_setopt (s5r->curl,
2013  CURLOPT_READFUNCTION,
2014  &curl_upload_cb));
2015  curl_easy_setopt (s5r->curl,
2016  CURLOPT_READDATA,
2017  s5r);
2018  {
2019  const char *us;
2020  long upload_size = 0;
2021 
2022  us = MHD_lookup_connection_value (con,
2023  MHD_HEADER_KIND,
2024  MHD_HTTP_HEADER_CONTENT_LENGTH);
2025  if ((1 == sscanf (us,
2026  "%ld",
2027  &upload_size)) &&
2028  (upload_size >= 0))
2029  {
2030  curl_easy_setopt (s5r->curl,
2031  CURLOPT_INFILESIZE,
2032  upload_size);
2033  }
2034  }
2035  }
2036  else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_POST))
2037  {
2039  curl_easy_setopt (s5r->curl,
2040  CURLOPT_POST,
2041  1L);
2042  curl_easy_setopt (s5r->curl,
2043  CURLOPT_WRITEFUNCTION,
2044  &curl_download_cb);
2045  curl_easy_setopt (s5r->curl,
2046  CURLOPT_WRITEDATA,
2047  s5r);
2048  curl_easy_setopt (s5r->curl,
2049  CURLOPT_READFUNCTION,
2050  &curl_upload_cb);
2051  curl_easy_setopt (s5r->curl,
2052  CURLOPT_READDATA,
2053  s5r);
2054  {
2055  const char *us;
2056  long upload_size;
2057 
2058  upload_size = 0;
2059  us = MHD_lookup_connection_value (con,
2060  MHD_HEADER_KIND,
2061  MHD_HTTP_HEADER_CONTENT_LENGTH);
2062  if ((NULL != us) &&
2063  (1 == sscanf (us,
2064  "%ld",
2065  &upload_size)) &&
2066  (upload_size >= 0))
2067  {
2068  curl_easy_setopt (s5r->curl,
2069  CURLOPT_INFILESIZE,
2070  upload_size);
2071  }
2072  else
2073  {
2074  curl_easy_setopt (s5r->curl,
2075  CURLOPT_INFILESIZE,
2076  upload_size);
2077  }
2078  }
2079  }
2080  else if (0 == strcasecmp (meth,
2081  MHD_HTTP_METHOD_HEAD))
2082  {
2084  curl_easy_setopt (s5r->curl,
2085  CURLOPT_NOBODY,
2086  1L);
2087  }
2088  else if (0 == strcasecmp (meth,
2089  MHD_HTTP_METHOD_OPTIONS))
2090  {
2092  curl_easy_setopt (s5r->curl,
2093  CURLOPT_CUSTOMREQUEST,
2094  "OPTIONS");
2095  curl_easy_setopt (s5r->curl,
2096  CURLOPT_WRITEFUNCTION,
2097  &curl_download_cb);
2098  curl_easy_setopt (s5r->curl,
2099  CURLOPT_WRITEDATA,
2100  s5r);
2101  }
2102  else if (0 == strcasecmp (meth,
2103  MHD_HTTP_METHOD_GET))
2104  {
2106  curl_easy_setopt (s5r->curl,
2107  CURLOPT_HTTPGET,
2108  1L);
2109  curl_easy_setopt (s5r->curl,
2110  CURLOPT_WRITEFUNCTION,
2111  &curl_download_cb);
2112  curl_easy_setopt (s5r->curl,
2113  CURLOPT_WRITEDATA,
2114  s5r);
2115  }
2116  else if (0 == strcasecmp (meth,
2117  MHD_HTTP_METHOD_DELETE))
2118  {
2120  curl_easy_setopt (s5r->curl,
2121  CURLOPT_CUSTOMREQUEST,
2122  "DELETE");
2123  curl_easy_setopt (s5r->curl,
2124  CURLOPT_WRITEFUNCTION,
2125  &curl_download_cb);
2126  curl_easy_setopt (s5r->curl,
2127  CURLOPT_WRITEDATA,
2128  s5r);
2129  }
2130  else
2131  {
2133  _ ("Unsupported HTTP method `%s'\n"),
2134  meth);
2135  curl_easy_cleanup (s5r->curl);
2136  s5r->curl = NULL;
2137  return MHD_NO;
2138  }
2139 
2140  if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_0))
2141  {
2142  curl_easy_setopt (s5r->curl,
2143  CURLOPT_HTTP_VERSION,
2144  CURL_HTTP_VERSION_1_0);
2145  }
2146  else if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_1))
2147  {
2148  curl_easy_setopt (s5r->curl,
2149  CURLOPT_HTTP_VERSION,
2150  CURL_HTTP_VERSION_1_1);
2151  }
2152  else
2153  {
2154  curl_easy_setopt (s5r->curl,
2155  CURLOPT_HTTP_VERSION,
2156  CURL_HTTP_VERSION_NONE);
2157  }
2158 
2159  if (GNUNET_YES == s5r->is_tls) // (HTTPS_PORT == s5r->port)
2160  {
2161  curl_easy_setopt (s5r->curl,
2162  CURLOPT_USE_SSL,
2163  CURLUSESSL_ALL);
2164  if (0 < s5r->num_danes)
2165  curl_easy_setopt (s5r->curl,
2166  CURLOPT_SSL_VERIFYPEER,
2167  0L);
2168  else
2169  curl_easy_setopt (s5r->curl,
2170  CURLOPT_SSL_VERIFYPEER,
2171  1L);
2172  /* Disable cURL checking the hostname, as we will check ourselves
2173  as only we have the domain name or the LEHO or the DANE record */
2174  curl_easy_setopt (s5r->curl,
2175  CURLOPT_SSL_VERIFYHOST,
2176  0L);
2177  }
2178  else
2179  {
2180  curl_easy_setopt (s5r->curl,
2181  CURLOPT_USE_SSL,
2182  CURLUSESSL_NONE);
2183  }
2184 
2185  if (CURLM_OK !=
2186  curl_multi_add_handle (curl_multi,
2187  s5r->curl))
2188  {
2189  GNUNET_break (0);
2190  curl_easy_cleanup (s5r->curl);
2191  s5r->curl = NULL;
2192  return MHD_NO;
2193  }
2194  MHD_get_connection_values (con,
2195  MHD_HEADER_KIND,
2196  (MHD_KeyValueIterator) & con_val_iter,
2197  s5r);
2198  curl_easy_setopt (s5r->curl,
2199  CURLOPT_HTTPHEADER,
2200  s5r->headers);
2202  return MHD_YES;
2203  }
2204 
2205  /* continuing to process request */
2206  if (0 != *upload_data_size)
2207  {
2209  "Processing %u bytes UPLOAD\n",
2210  (unsigned int) *upload_data_size);
2211 
2212  /* FIXME: This must be set or a header with Transfer-Encoding: chunked. Else
2213  * upload callback is not called!
2214  */
2215  curl_easy_setopt (s5r->curl,
2216  CURLOPT_POSTFIELDSIZE,
2217  *upload_data_size);
2218 
2219  left = GNUNET_MIN (*upload_data_size,
2220  sizeof(s5r->io_buf) - s5r->io_len);
2221  GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
2222  upload_data,
2223  left);
2224  s5r->io_len += left;
2225  *upload_data_size -= left;
2226  GNUNET_assert (NULL != s5r->curl);
2227  if (GNUNET_YES == s5r->curl_paused)
2228  {
2229  s5r->curl_paused = GNUNET_NO;
2230  curl_easy_pause (s5r->curl,
2231  CURLPAUSE_CONT);
2232  }
2233  return MHD_YES;
2234  }
2235  if (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state)
2236  {
2238  "Finished processing UPLOAD\n");
2240  }
2241  if (NULL == s5r->response)
2242  {
2244  "Waiting for HTTP response for %s%s...\n",
2245  s5r->domain,
2246  s5r->url);
2247  MHD_suspend_connection (con);
2248  s5r->suspended = GNUNET_YES;
2249  return MHD_YES;
2250  }
2252  "Queueing response for %s%s with MHD\n",
2253  s5r->domain,
2254  s5r->url);
2255  run_mhd_now (s5r->hd);
2256  return MHD_queue_response (con,
2257  s5r->response_code,
2258  s5r->response);
2259 }
Socket has been passed to MHD, do not close it anymore.
int GNUNET_snprintf(char *buf, size_t size, const char *format,...)
Like snprintf, just aborts if the buffer is of insufficient size.
struct MHD_Connection * con
MHD connection for this request.
static size_t curl_check_hdr(void *buffer, size_t size, size_t nmemb, void *cls)
We&#39;re getting an HTTP response header from cURL.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static struct MHD_Response * curl_failure_response
Response we return on cURL failures.
int curl_paused
Did we pause CURL processing?
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_NO
Definition: gnunet_common.h:78
We&#39;ve started receiving upload data from MHD.
We&#39;ve finished receiving upload data from MHD.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
size_t io_len
Number of bytes already in the IO buffer.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
static uint16_t port
The port the proxy is running on (default 7777)
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
int suspended
Did we suspend MHD processing?
unsigned int num_danes
Number of entries used in dane_data_len and dane_data.
struct curl_slist * headers
HTTP request headers for the curl request.
enum SocksPhase state
The socks state.
struct MhdHttpList * hd
MHD HTTP instance handling this request, NULL for none.
#define GNUNET_MIN(a, b)
Definition: gnunet_common.h:80
char * domain
the domain name to server (only important for TLS)
struct MHD_Response * response
MHD response object for this request.
uint16_t port
Desired destination port.
struct sockaddr_storage destination_address
Once known, what&#39;s the target address for the connection?
struct curl_slist * hosts
DNS->IP mappings resolved through GNS.
static int con_val_iter(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
Read HTTP request header field from the request.
static size_t curl_download_cb(void *ptr, size_t size, size_t nmemb, void *ctx)
Handle response payload data from cURL.
We&#39;ve finished uploading data via CURL and can now download.
int is_gns
Was the hostname resolved via GNS?
char * leho
DNS Legacy Host Name as given by GNS, NULL if not given.
static void curl_download_prepare()
Ask cURL for the select() sets and schedule cURL operations.
#define GNUNET_log(kind,...)
char io_buf[CURL_MAX_WRITE_SIZE]
Buffer we use for moving data between MHD and curl (in both directions).
int is_tls
This is (probably) a TLS connection.
#define GNUNET_YES
Definition: gnunet_common.h:77
char * url
The URL to fetch.
A structure for socks requests.
static CURLM * curl_multi
The cURL multi handle.
static void run_mhd_now(struct MhdHttpList *hd)
Run MHD now, we have extra data ready for the callback.
unsigned int response_code
HTTP response code to give to MHD for the response.
static size_t curl_upload_cb(void *buf, size_t size, size_t nmemb, void *cls)
cURL callback for uploaded (PUT/POST) data.
#define GNUNET_free(ptr)
Wrapper around free.
CURL * curl
Handle to cURL.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mhd_completed_cb()

static void mhd_completed_cb ( void *  cls,
struct MHD_Connection *  connection,
void **  con_cls,
enum MHD_RequestTerminationCode  toe 
)
static

Function called when MHD decides that we are done with a request.

Parameters
clsNULL
connectionconnection handle
con_clsvalue as set by the last call to the MHD_AccessHandlerCallback, should be our struct Socks5Request *
toereason for request termination (ignored)

Definition at line 2275 of file gnunet-gns-proxy.c.

References Socks5Request::curl, curl_download_prepare(), curl_failure_response, curl_multi, GNUNET_CONTAINER_DLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_free, GNUNET_log, Socks5Request::header_head, Socks5Request::header_tail, Socks5Request::headers, Socks5Request::io_len, Socks5Request::rbuf_len, Socks5Request::response, SOCKS5_SOCKET_WITH_MHD, Socks5Request::state, Socks5Request::url, and Socks5Request::wbuf_len.

Referenced by lookup_ssl_httpd(), and run().

2279 {
2280  struct Socks5Request *s5r = *con_cls;
2281 
2282  if (NULL == s5r)
2283  return;
2284  if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
2286  "MHD encountered error handling request: %d\n",
2287  toe);
2288  if (NULL != s5r->curl)
2289  {
2291  "Removing cURL handle (MHD interaction complete)\n");
2292  curl_multi_remove_handle (curl_multi,
2293  s5r->curl);
2294  curl_slist_free_all (s5r->headers);
2295  s5r->headers = NULL;
2296  curl_easy_reset (s5r->curl);
2297  s5r->rbuf_len = 0;
2298  s5r->wbuf_len = 0;
2299  s5r->io_len = 0;
2301  }
2302  if ((NULL != s5r->response) &&
2303  (curl_failure_response != s5r->response))
2304  MHD_destroy_response (s5r->response);
2305  for (struct HttpResponseHeader *header = s5r->header_head;
2306  NULL != header;
2307  header = s5r->header_head)
2308  {
2310  s5r->header_tail,
2311  header);
2312  GNUNET_free (header->type);
2313  GNUNET_free (header->value);
2314  GNUNET_free (header);
2315  }
2317  "Finished request for %s\n",
2318  s5r->url);
2319  GNUNET_free (s5r->url);
2321  s5r->url = NULL;
2322  s5r->response = NULL;
2323  *con_cls = NULL;
2324 }
struct HttpResponseHeader * header_head
Headers from response.
Socket has been passed to MHD, do not close it anymore.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static struct MHD_Response * curl_failure_response
Response we return on cURL failures.
size_t io_len
Number of bytes already in the IO buffer.
size_t rbuf_len
Number of bytes already in read buffer.
A header list.
struct HttpResponseHeader * header_tail
Headers from response.
struct curl_slist * headers
HTTP request headers for the curl request.
enum SocksPhase state
The socks state.
struct MHD_Response * response
MHD response object for this request.
static void curl_download_prepare()
Ask cURL for the select() sets and schedule cURL operations.
#define GNUNET_log(kind,...)
char * url
The URL to fetch.
A structure for socks requests.
static CURLM * curl_multi
The cURL multi handle.
#define GNUNET_free(ptr)
Wrapper around free.
CURL * curl
Handle to cURL.
size_t wbuf_len
Number of bytes already in write buffer.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mhd_connection_cb()

static void mhd_connection_cb ( void *  cls,
struct MHD_Connection *  connection,
void **  con_cls,
enum MHD_ConnectionNotificationCode  cnc 
)
static

Function called when MHD connection is opened or closed.

Parameters
clsNULL
connectionconnection handle
con_clsvalue as set by the last call to the MHD_AccessHandlerCallback, should be our struct Socks5Request *
toeconnection notification type

Definition at line 2337 of file gnunet-gns-proxy.c.

References cleanup_s5r(), curl_download_prepare(), GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_NETWORK_get_fd(), GNUNET_NO, Socks5Request::next, Socks5Request::sock, and Socks5Request::ssl_checked.

Referenced by lookup_ssl_httpd(), and run().

2341 {
2342  struct Socks5Request *s5r;
2343  const union MHD_ConnectionInfo *ci;
2344  int sock;
2345 
2346  switch (cnc)
2347  {
2348  case MHD_CONNECTION_NOTIFY_STARTED:
2349  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
2350  ci = MHD_get_connection_info (connection,
2351  MHD_CONNECTION_INFO_CONNECTION_FD);
2352  if (NULL == ci)
2353  {
2354  GNUNET_break (0);
2355  return;
2356  }
2357  sock = ci->connect_fd;
2358  for (s5r = s5r_head; NULL != s5r; s5r = s5r->next)
2359  {
2360  if (GNUNET_NETWORK_get_fd (s5r->sock) == sock)
2361  {
2363  "Context set...\n");
2364  s5r->ssl_checked = GNUNET_NO;
2365  *con_cls = s5r;
2366  break;
2367  }
2368  }
2369  break;
2370 
2371  case MHD_CONNECTION_NOTIFY_CLOSED:
2373  "Connection closed... cleaning up\n");
2374  s5r = *con_cls;
2375  if (NULL == s5r)
2376  {
2378  "Connection stale!\n");
2379  return;
2380  }
2381  cleanup_s5r (s5r);
2383  *con_cls = NULL;
2384  break;
2385 
2386  default:
2387  GNUNET_break (0);
2388  }
2389 }
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition: network.c:1080
struct GNUNET_NETWORK_Handle * sock
The client socket.
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
int ssl_checked
X.509 Certificate status.
struct Socks5Request * next
DLL.
static struct Socks5Request * s5r_head
DLL of active socks requests.
static void cleanup_s5r(struct Socks5Request *s5r)
Clean up s5r handles.
static void curl_download_prepare()
Ask cURL for the select() sets and schedule cURL operations.
#define GNUNET_log(kind,...)
A structure for socks requests.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mhd_log_callback()

static void* mhd_log_callback ( void *  cls,
const char *  url,
struct MHD_Connection *  connection 
)
static

Function called when MHD first processes an incoming connection.

Gives us the respective URI information.

We use this to associate the struct MHD_Connection with our internal struct Socks5Request data structure (by checking for matching sockets).

Parameters
clsthe HTTP server handle (a struct MhdHttpList)
urlthe URL that is being requested
connectionMHD connection object for the request
Returns
the struct Socks5Request that this connection is for

Definition at line 2406 of file gnunet-gns-proxy.c.

References GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_SCHEDULER_cancel(), GNUNET_strdup, SOCKS5_SOCKET_WITH_MHD, Socks5Request::state, Socks5Request::timeout_task, and Socks5Request::url.

Referenced by lookup_ssl_httpd(), and run().

2409 {
2410  struct Socks5Request *s5r;
2411  const union MHD_ConnectionInfo *ci;
2412 
2413  ci = MHD_get_connection_info (connection,
2414  MHD_CONNECTION_INFO_SOCKET_CONTEXT);
2415  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
2416  if (NULL == ci)
2417  {
2418  GNUNET_break (0);
2419  return NULL;
2420  }
2421  s5r = ci->socket_context;
2422  if (NULL != s5r->url)
2423  {
2424  GNUNET_break (0);
2425  return NULL;
2426  }
2427  s5r->url = GNUNET_strdup (url);
2428  if (NULL != s5r->timeout_task)
2429  {
2431  s5r->timeout_task = NULL;
2432  }
2434  return s5r;
2435 }
Socket has been passed to MHD, do not close it anymore.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
enum SocksPhase state
The socks state.
struct GNUNET_SCHEDULER_Task * timeout_task
Timeout task.
#define GNUNET_log(kind,...)
char * url
The URL to fetch.
A structure for socks requests.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:966
Here is the call graph for this function:
Here is the caller graph for this function:

◆ kill_httpd()

static void kill_httpd ( struct MhdHttpList hd)
static

Kill the given MHD daemon.

Parameters
hddaemon to stop

Definition at line 2444 of file gnunet-gns-proxy.c.

References MhdHttpList::daemon, MhdHttpList::domain, GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_free_non_null, GNUNET_SCHEDULER_cancel(), MhdHttpList::httpd_task, and MhdHttpList::proxy_cert.

Referenced by do_shutdown(), kill_httpd_task(), and schedule_httpd().

2445 {
2448  hd);
2450  MHD_stop_daemon (hd->daemon);
2451  if (NULL != hd->httpd_task)
2452  {
2454  hd->httpd_task = NULL;
2455  }
2457  if (hd == httpd)
2458  httpd = NULL;
2459  GNUNET_free (hd);
2460 }
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
char * domain
the domain name to server (only important for TLS)
static struct MhdHttpList * mhd_httpd_tail
DLL for http/https daemons.
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
static struct MhdHttpList * httpd
Daemon for HTTP (we have one per X.509 certificate, and then one for all HTTP connections; this is th...
struct MHD_Daemon * daemon
The daemon handle.
static struct MhdHttpList * mhd_httpd_head
DLL for http/https daemons.
struct ProxyGNSCertificate * proxy_cert
Optional proxy certificate used.
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_SCHEDULER_Task * httpd_task
The task ID.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:966
Here is the call graph for this function:
Here is the caller graph for this function:

◆ kill_httpd_task()

static void kill_httpd_task ( void *  cls)
static

Task run whenever HTTP server is idle for too long.

Kill it.

Parameters
clsthe struct MhdHttpList *

Definition at line 2469 of file gnunet-gns-proxy.c.

References do_httpd(), MhdHttpList::httpd_task, and kill_httpd().

Referenced by schedule_httpd().

2470 {
2471  struct MhdHttpList *hd = cls;
2472 
2473  hd->httpd_task = NULL;
2474  kill_httpd (hd);
2475 }
A structure for all running Httpds.
static void kill_httpd(struct MhdHttpList *hd)
Kill the given MHD daemon.
struct GNUNET_SCHEDULER_Task * httpd_task
The task ID.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ do_httpd()

static void do_httpd ( void *  cls)
static

Task run whenever HTTP server operations are pending.

Parameters
clsthe struct MhdHttpList * of the daemon that is being run
clsthe struct MhdHttpList of the daemon that is being run

Definition at line 2573 of file gnunet-gns-proxy.c.

References MhdHttpList::daemon, MhdHttpList::httpd_task, and schedule_httpd().

Referenced by kill_httpd_task(), run_mhd_now(), and schedule_httpd().

2574 {
2575  struct MhdHttpList *hd = cls;
2576 
2577  hd->httpd_task = NULL;
2578  MHD_run (hd->daemon);
2579  schedule_httpd (hd);
2580 }
static void schedule_httpd(struct MhdHttpList *hd)
Schedule MHD.
struct MHD_Daemon * daemon
The daemon handle.
A structure for all running Httpds.
struct GNUNET_SCHEDULER_Task * httpd_task
The task ID.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ schedule_httpd()

static void schedule_httpd ( struct MhdHttpList hd)
static

Schedule MHD.

This function should be called initially when an MHD is first getting its client socket, and will then automatically always be called later whenever there is work to be done.

Parameters
hdthe daemon to schedule

Definition at line 2495 of file gnunet-gns-proxy.c.

References MhdHttpList::daemon, do_httpd(), GNUNET_NETWORK_fdset_copy_native(), GNUNET_NETWORK_fdset_create(), GNUNET_NETWORK_fdset_destroy(), GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_add_select(), GNUNET_SCHEDULER_cancel(), GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_UNIT_FOREVER_REL, MhdHttpList::httpd_task, kill_httpd(), kill_httpd_task(), MHD_CACHE_TIMEOUT, GNUNET_TIME_Relative::rel_value_us, and timeout.

Referenced by do_httpd(), and setup_data_transfer().

2496 {
2497  fd_set rs;
2498  fd_set ws;
2499  fd_set es;
2500  struct GNUNET_NETWORK_FDSet *wrs;
2501  struct GNUNET_NETWORK_FDSet *wws;
2502  int max;
2503  int haveto;
2504  MHD_UNSIGNED_LONG_LONG timeout;
2505  struct GNUNET_TIME_Relative tv;
2506 
2507  FD_ZERO (&rs);
2508  FD_ZERO (&ws);
2509  FD_ZERO (&es);
2510  max = -1;
2511  if (MHD_YES !=
2512  MHD_get_fdset (hd->daemon,
2513  &rs,
2514  &ws,
2515  &es,
2516  &max))
2517  {
2518  kill_httpd (hd);
2519  return;
2520  }
2521  haveto = MHD_get_timeout (hd->daemon,
2522  &timeout);
2523  if (MHD_YES == haveto)
2524  tv.rel_value_us = (uint64_t) timeout * 1000LL;
2525  else
2527  if (-1 != max)
2528  {
2529  wrs = GNUNET_NETWORK_fdset_create ();
2530  wws = GNUNET_NETWORK_fdset_create ();
2531  GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
2532  GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
2533  }
2534  else
2535  {
2536  wrs = NULL;
2537  wws = NULL;
2538  }
2539  if (NULL != hd->httpd_task)
2540  {
2542  hd->httpd_task = NULL;
2543  }
2544  if ((MHD_YES != haveto) &&
2545  (-1 == max) &&
2546  (hd != httpd))
2547  {
2548  /* daemon is idle, kill after timeout */
2550  &kill_httpd_task,
2551  hd);
2552  }
2553  else
2554  {
2555  hd->httpd_task =
2557  tv, wrs, wws,
2558  &do_httpd, hd);
2559  }
2560  if (NULL != wrs)
2562  if (NULL != wws)
2564 }
#define MHD_CACHE_TIMEOUT
After how long do we clean up unused MHD TLS instances?
static void kill_httpd_task(void *cls)
Task run whenever HTTP server is idle for too long.
void GNUNET_NETWORK_fdset_copy_native(struct GNUNET_NETWORK_FDSet *to, const fd_set *from, int nfds)
Copy a native fd set into the GNUnet representation.
Definition: network.c:1120
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1266
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1253
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1250
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
static struct MhdHttpList * httpd
Daemon for HTTP (we have one per X.509 certificate, and then one for all HTTP connections; this is th...
collection of IO descriptors
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_select(enum GNUNET_SCHEDULER_Priority prio, struct GNUNET_TIME_Relative delay, const struct GNUNET_NETWORK_FDSet *rs, const struct GNUNET_NETWORK_FDSet *ws, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when any of the specified file descriptor set...
Definition: scheduler.c:1810
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct MHD_Daemon * daemon
The daemon handle.
static void kill_httpd(struct MhdHttpList *hd)
Kill the given MHD daemon.
static void do_httpd(void *cls)
Task run whenever HTTP server operations are pending.
Run with the default priority (normal P2P operations).
struct GNUNET_SCHEDULER_Task * httpd_task
The task ID.
Time for relative time used by GNUnet, in microseconds.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:966
Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_file()

static void* load_file ( const char *  filename,
unsigned int *  size 
)
static

Read file in filename.

Parameters
filenamefile to read
sizepointer where filesize is stored
Returns
NULL on error

Definition at line 2606 of file gnunet-gns-proxy.c.

References GNUNET_DISK_file_size(), GNUNET_DISK_fn_read(), GNUNET_free, GNUNET_malloc, GNUNET_OK, GNUNET_YES, and MAX_PEM_SIZE.

Referenced by load_cert_from_file(), and load_key_from_file().

2608 {
2609  void *buffer;
2610  uint64_t fsize;
2611 
2612  if (GNUNET_OK !=
2614  &fsize,
2615  GNUNET_YES,
2616  GNUNET_YES))
2617  return NULL;
2618  if (fsize > MAX_PEM_SIZE)
2619  return NULL;
2620  *size = (unsigned int) fsize;
2621  buffer = GNUNET_malloc (*size);
2622  if (fsize !=
2624  buffer,
2625  (size_t) fsize))
2626  {
2627  GNUNET_free (buffer);
2628  return NULL;
2629  }
2630  return buffer;
2631 }
#define MAX_PEM_SIZE
Largest allowed size for a PEM certificate.
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
static char * filename
static unsigned int size
Size of the "table".
Definition: peer.c:67
int GNUNET_DISK_file_size(const char *filename, uint64_t *size, int include_symbolic_links, int single_file_mode)
Get the size of the file (or directory) of the given file (in bytes).
Definition: disk.c:257
#define GNUNET_YES
Definition: gnunet_common.h:77
#define GNUNET_malloc(size)
Wrapper around malloc.
ssize_t GNUNET_DISK_fn_read(const char *fn, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:794
#define GNUNET_free(ptr)
Wrapper around free.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_key_from_file()

static int load_key_from_file ( gnutls_x509_privkey_t  key,
const char *  keyfile 
)
static

Load PEM key from file.

Parameters
keywhere to store the data
keyfilepath to the PEM file
Returns
GNUNET_OK on success

Definition at line 2642 of file gnunet-gns-proxy.c.

References _, GNUNET_ERROR_TYPE_ERROR, GNUNET_free_non_null, GNUNET_log, GNUNET_OK, GNUNET_SYSERR, load_file(), and ret.

Referenced by run().

2644 {
2645  gnutls_datum_t key_data;
2646  int ret;
2647 
2648  key_data.data = load_file (keyfile,
2649  &key_data.size);
2650  if (NULL == key_data.data)
2651  return GNUNET_SYSERR;
2652  ret = gnutls_x509_privkey_import (key, &key_data,
2653  GNUTLS_X509_FMT_PEM);
2654  if (GNUTLS_E_SUCCESS != ret)
2655  {
2657  _ ("Unable to import private key from file `%s'\n"),
2658  keyfile);
2659  }
2660  GNUNET_free_non_null (key_data.data);
2661  return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2662 }
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
static void * load_file(const char *filename, unsigned int *size)
Read file in filename.
struct GNUNET_HashCode key
The key used in the DHT.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
#define GNUNET_log(kind,...)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_cert_from_file()

static int load_cert_from_file ( gnutls_x509_crt_t  crt,
const char *  certfile 
)
static

Load cert from file.

Parameters
crtstruct to store data in
certfilepath to pem file
Returns
GNUNET_OK on success

Definition at line 2673 of file gnunet-gns-proxy.c.

References _, GNUNET_ERROR_TYPE_ERROR, GNUNET_free_non_null, GNUNET_log, GNUNET_OK, GNUNET_SYSERR, load_file(), and ret.

Referenced by run().

2675 {
2676  gnutls_datum_t cert_data;
2677  int ret;
2678 
2679  cert_data.data = load_file (certfile,
2680  &cert_data.size);
2681  if (NULL == cert_data.data)
2682  return GNUNET_SYSERR;
2683  ret = gnutls_x509_crt_import (crt,
2684  &cert_data,
2685  GNUTLS_X509_FMT_PEM);
2686  if (GNUTLS_E_SUCCESS != ret)
2687  {
2689  _ ("Unable to import certificate from `%s'\n"),
2690  certfile);
2691  }
2692  GNUNET_free_non_null (cert_data.data);
2693  return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2694 }
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
static void * load_file(const char *filename, unsigned int *size)
Read file in filename.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
#define GNUNET_log(kind,...)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ generate_gns_certificate()

static struct ProxyGNSCertificate* generate_gns_certificate ( const char *  name)
static

Generate new certificate for specific name.

Parameters
namethe subject name to generate a cert for
Returns
a struct holding the PEM data, NULL on error

Definition at line 2704 of file gnunet-gns-proxy.c.

References ProxyCA::cert, ProxyGNSCertificate::cert, etime, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_new, ProxyCA::key, ProxyGNSCertificate::key, proxy_ca, and request.

Referenced by lookup_ssl_httpd().

2705 {
2706  unsigned int serial;
2707  size_t key_buf_size;
2708  size_t cert_buf_size;
2709  gnutls_x509_crt_t request;
2710  time_t etime;
2711  struct tm *tm_data;
2712  struct ProxyGNSCertificate *pgc;
2713 
2715  "Generating x.509 certificate for `%s'\n",
2716  name);
2717  GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_init (&request));
2718  GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_set_key (request,
2719  proxy_ca.key));
2720  pgc = GNUNET_new (struct ProxyGNSCertificate);
2721  gnutls_x509_crt_set_dn_by_oid (request,
2722  GNUTLS_OID_X520_COUNTRY_NAME,
2723  0,
2724  "ZZ",
2725  strlen ("ZZ"));
2726  gnutls_x509_crt_set_dn_by_oid (request,
2727  GNUTLS_OID_X520_ORGANIZATION_NAME,
2728  0,
2729  "GNU Name System",
2730  strlen ("GNU Name System"));
2731  gnutls_x509_crt_set_dn_by_oid (request,
2732  GNUTLS_OID_X520_COMMON_NAME,
2733  0,
2734  name,
2735  strlen (name));
2736  gnutls_x509_crt_set_subject_alternative_name (request,
2737  GNUTLS_SAN_DNSNAME,
2738  name);
2739  GNUNET_break (GNUTLS_E_SUCCESS ==
2740  gnutls_x509_crt_set_version (request,
2741  3));
2742  gnutls_rnd (GNUTLS_RND_NONCE,
2743  &serial,
2744  sizeof(serial));
2745  gnutls_x509_crt_set_serial (request,
2746  &serial,
2747  sizeof(serial));
2748  etime = time (NULL);
2749  tm_data = localtime (&etime);
2750  tm_data->tm_hour--;
2751  etime = mktime (tm_data);
2752  gnutls_x509_crt_set_activation_time (request,
2753  etime);
2754  tm_data->tm_year++;
2755  etime = mktime (tm_data);
2756  gnutls_x509_crt_set_expiration_time (request,
2757  etime);
2758  gnutls_x509_crt_sign2 (request,
2759  proxy_ca.cert,
2760  proxy_ca.key,
2761  GNUTLS_DIG_SHA512,
2762  0);
2763  key_buf_size = sizeof(pgc->key);
2764  cert_buf_size = sizeof(pgc->cert);
2765  gnutls_x509_crt_export (request,
2766  GNUTLS_X509_FMT_PEM,
2767  pgc->cert,
2768  &cert_buf_size);
2769  gnutls_x509_privkey_export (proxy_ca.key,
2770  GNUTLS_X509_FMT_PEM,
2771  pgc->key,
2772  &key_buf_size);
2773  gnutls_x509_crt_deinit (request);
2774  return pgc;
2775 }
static struct GNUNET_VPN_RedirectionRequest * request
Opaque redirection request handle.
Definition: gnunet-vpn.c:41
#define GNUNET_new(type)
Allocate a struct or union of the given type.
static struct ProxyCA proxy_ca
The CA for X.509 certificate generation.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
char key[(10 *1024)]
The private key as PEM.
char cert[(10 *1024)]
The certificate as PEM.
gnutls_x509_privkey_t key
The private key.
const char * name
#define GNUNET_log(kind,...)
gnutls_x509_crt_t cert
The certificate.
static uint64_t etime
Expiration string converted to numeric value.
Definition: gnunet-abd.c:201
Structure for GNS certificates.
Here is the caller graph for this function:

◆ mhd_error_log_callback()

static void mhd_error_log_callback ( void *  cls,
const char *  fm,
va_list  ap 
)
static

Function called by MHD with errors, suppresses them all.

Parameters
clsclosure
fmformat string (printf()-style)
aparguments to fm

Definition at line 2786 of file gnunet-gns-proxy.c.

Referenced by lookup_ssl_httpd().

2789 {
2790  /* do nothing */
2791 }
Here is the caller graph for this function:

◆ lookup_ssl_httpd()

static struct MhdHttpList* lookup_ssl_httpd ( const char *  domain)
static

Lookup (or create) an TLS MHD instance for a particular domain.

Parameters
domainthe domain the TLS daemon has to serve
Returns
NULL on error

Definition at line 2801 of file gnunet-gns-proxy.c.

References ProxyGNSCertificate::cert, create_response(), MhdHttpList::daemon, MhdHttpList::domain, generate_gns_certificate(), GNUNET_break, GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_new, GNUNET_strdup, GNUNET_YES, MhdHttpList::is_ssl, ProxyGNSCertificate::key, mhd_completed_cb(), mhd_connection_cb(), mhd_error_log_callback(), mhd_log_callback(), MhdHttpList::next, and MhdHttpList::proxy_cert.

Referenced by setup_data_transfer().

2802 {
2803  struct MhdHttpList *hd;
2804  struct ProxyGNSCertificate *pgc;
2805 
2806  if (NULL == domain)
2807  {
2808  GNUNET_break (0);
2809  return NULL;
2810  }
2811  for (hd = mhd_httpd_head; NULL != hd; hd = hd->next)
2812  if ((NULL != hd->domain) &&
2813  (0 == strcmp (hd->domain, domain)))
2814  return hd;
2816  "Starting fresh MHD HTTPS instance for domain `%s'\n",
2817  domain);
2818  pgc = generate_gns_certificate (domain);
2819  hd = GNUNET_new (struct MhdHttpList);
2820  hd->is_ssl = GNUNET_YES;
2821  hd->domain = GNUNET_strdup (domain);
2822  hd->proxy_cert = pgc;
2823  hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL
2824  | MHD_USE_NO_LISTEN_SOCKET
2825  | MHD_ALLOW_SUSPEND_RESUME,
2826  0,
2827  NULL, NULL,
2828  &create_response, hd,
2829  MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
2830  int) 16,
2831  MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
2832  NULL,
2833  MHD_OPTION_NOTIFY_CONNECTION,
2834  &mhd_connection_cb, NULL,
2835  MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
2836  NULL,
2837  MHD_OPTION_EXTERNAL_LOGGER,
2838  &mhd_error_log_callback, NULL,
2839  MHD_OPTION_HTTPS_MEM_KEY, pgc->key,
2840  MHD_OPTION_HTTPS_MEM_CERT, pgc->cert,
2841  MHD_OPTION_END);
2842  if (NULL == hd->daemon)
2843  {
2844  GNUNET_free (pgc);
2845  GNUNET_free (hd);
2846  return NULL;
2847  }
2850  hd);
2851  return hd;
2852 }
static void mhd_connection_cb(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_ConnectionNotificationCode cnc)
Function called when MHD connection is opened or closed.
char * domain
the domain name to server (only important for TLS)
static struct MhdHttpList * mhd_httpd_tail
DLL for http/https daemons.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
static void mhd_error_log_callback(void *cls, const char *fm, va_list ap)
Function called by MHD with errors, suppresses them all.
static void * mhd_log_callback(void *cls, const char *url, struct MHD_Connection *connection)
Function called when MHD first processes an incoming connection.
struct MhdHttpList * next
DLL for httpds.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
static void mhd_completed_cb(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe)
Function called when MHD decides that we are done with a request.
int is_ssl
is this an ssl daemon?
struct MHD_Daemon * daemon
The daemon handle.
char key[(10 *1024)]
The private key as PEM.
char cert[(10 *1024)]
The certificate as PEM.
A structure for all running Httpds.
static struct MhdHttpList * mhd_httpd_head
DLL for http/https daemons.
struct ProxyGNSCertificate * proxy_cert
Optional proxy certificate used.
#define GNUNET_log(kind,...)
#define GNUNET_YES
Definition: gnunet_common.h:77
static struct ProxyGNSCertificate * generate_gns_certificate(const char *name)
Generate new certificate for specific name.
static int create_response(void *cls, struct MHD_Connection *con, const char *url, const char *meth, const char *ver, const char *upload_data, size_t *upload_data_size, void **con_cls)
Main MHD callback for handling requests.
Structure for GNS certificates.
#define GNUNET_free(ptr)
Wrapper around free.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ timeout_s5r_handshake()

static void timeout_s5r_handshake ( void *  cls)
static

Task run when a Socks5Request somehow fails to be associated with an MHD connection (i.e.

because the client never speaks HTTP after the SOCKS5 handshake). Clean up.

Parameters
clsthe struct Socks5Request *

Definition at line 2863 of file gnunet-gns-proxy.c.

References cleanup_s5r(), and Socks5Request::timeout_task.

Referenced by setup_data_transfer().

2864 {
2865  struct Socks5Request *s5r = cls;
2866 
2867  s5r->timeout_task = NULL;
2868  cleanup_s5r (s5r);
2869 }
struct GNUNET_SCHEDULER_Task * timeout_task
Timeout task.
static void cleanup_s5r(struct Socks5Request *s5r)
Clean up s5r handles.
A structure for socks requests.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setup_data_transfer()

static void setup_data_transfer ( struct Socks5Request s5r)
static

We're done with the Socks5 protocol, now we need to pass the connection data through to the final destination, either direct (if the protocol might not be HTTP), or via MHD (if the port looks like it should be HTTP).

Parameters
s5rsocks request that has reached the final stage

Definition at line 2881 of file gnunet-gns-proxy.c.

References _, cleanup_s5r(), MhdHttpList::daemon, Socks5Request::domain, GNUNET_asprintf(), GNUNET_assert, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_free_non_null, GNUNET_log, GNUNET_NETWORK_get_addr(), GNUNET_NETWORK_get_addrlen(), GNUNET_NETWORK_get_fd(), GNUNET_SCHEDULER_add_delayed(), GNUNET_YES, Socks5Request::hd, HTTP_HANDSHAKE_TIMEOUT, httpd, Socks5Request::is_tls, len, lookup_ssl_httpd(), schedule_httpd(), Socks5Request::sock, SOCKS5_SOCKET_WITH_MHD, Socks5Request::state, timeout_s5r_handshake(), and Socks5Request::timeout_task.

Referenced by do_write().

2882 {
2883  struct MhdHttpList *hd;
2884  int fd;
2885  const struct sockaddr *addr;
2886  socklen_t len;
2887  char *domain;
2888 
2889  if (GNUNET_YES == s5r->is_tls)
2890  {
2891  GNUNET_asprintf (&domain,
2892  "%s",
2893  s5r->domain);
2894  hd = lookup_ssl_httpd (domain);
2895  if (NULL == hd)
2896  {
2898  _ ("Failed to start HTTPS server for `%s'\n"),
2899  s5r->domain);
2900  cleanup_s5r (s5r);
2901  GNUNET_free (domain);
2902  return;
2903  }
2904  }
2905  else
2906  {
2907  domain = NULL;
2908  GNUNET_assert (NULL != httpd);
2909  hd = httpd;
2910  }
2911  fd = GNUNET_NETWORK_get_fd (s5r->sock);
2912  addr = GNUNET_NETWORK_get_addr (s5r->sock);
2913  len = GNUNET_NETWORK_get_addrlen (s5r->sock);
2915  if (MHD_YES !=
2916  MHD_add_connection (hd->daemon,
2917  fd,
2918  addr,
2919  len))
2920  {
2922  _ ("Failed to pass client to MHD\n"));
2923  cleanup_s5r (s5r);
2924  GNUNET_free_non_null (domain);
2925  return;
2926  }
2927  s5r->hd = hd;
2928  schedule_httpd (hd);
2931  s5r);
2932  GNUNET_free_non_null (domain);
2933 }
Socket has been passed to MHD, do not close it anymore.
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition: network.c:1080
struct sockaddr * GNUNET_NETWORK_get_addr(const struct GNUNET_NETWORK_Handle *desc)
Return the sockaddr for this network handle.
Definition: network.c:1093
socklen_t GNUNET_NETWORK_get_addrlen(const struct GNUNET_NETWORK_Handle *desc)
Return sockaddr length for this network handle.
Definition: network.c:1106
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
struct GNUNET_NETWORK_Handle * sock
The client socket.
#define HTTP_HANDSHAKE_TIMEOUT
After how long do we clean up Socks5 handles that failed to show any activity with their respective M...
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1253
static struct MhdHttpList * httpd
Daemon for HTTP (we have one per X.509 certificate, and then one for all HTTP connections; this is th...
enum SocksPhase state
The socks state.
struct MhdHttpList * hd
MHD HTTP instance handling this request, NULL for none.
char * domain
the domain name to server (only important for TLS)
static void schedule_httpd(struct MhdHttpList *hd)
Schedule MHD.
struct MHD_Daemon * daemon
The daemon handle.
static struct MhdHttpList * lookup_ssl_httpd(const char *domain)
Lookup (or create) an TLS MHD instance for a particular domain.
struct GNUNET_SCHEDULER_Task * timeout_task
Timeout task.
static void cleanup_s5r(struct Socks5Request *s5r)
Clean up s5r handles.
A structure for all running Httpds.
#define GNUNET_log(kind,...)
int is_tls
This is (probably) a TLS connection.
static void timeout_s5r_handshake(void *cls)
Task run when a Socks5Request somehow fails to be associated with an MHD connection (i...
#define GNUNET_YES
Definition: gnunet_common.h:77
#define GNUNET_free(ptr)
Wrapper around free.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
Here is the call graph for this function:
Here is the caller graph for this function:

◆ do_write()

static void do_write ( void *  cls)
static

Write data from buffer to socks5 client, then continue with state machine.

Parameters
clsthe closure with the struct Socks5Request

Definition at line 2945 of file gnunet-gns-proxy.c.

References cleanup_s5r(), GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_NETWORK_socket_send(), GNUNET_SCHEDULER_add_write_net(), GNUNET_TIME_UNIT_FOREVER_REL, len, Socks5Request::rtask, setup_data_transfer(), Socks5Request::sock, SOCKS5_DATA_TRANSFER, SOCKS5_INIT, SOCKS5_REQUEST, SOCKS5_WRITE_THEN_CLEANUP, Socks5Request::state, Socks5Request::wbuf, Socks5Request::wbuf_len, and Socks5Request::wtask.

Referenced by do_s5r_read(), signal_socks_failure(), and signal_socks_success().

2946 {
2947  struct Socks5Request *s5r = cls;
2948  ssize_t len;
2949 
2950  s5r->wtask = NULL;
2951  len = GNUNET_NETWORK_socket_send (s5r->sock,
2952  s5r->wbuf,
2953  s5r->wbuf_len);
2954  if (len <= 0)
2955  {
2956  /* write error: connection closed, shutdown, etc.; just clean up */
2958  "Write Error\n");
2959  cleanup_s5r (s5r);
2960  return;
2961  }
2962  memmove (s5r->wbuf,
2963  &s5r->wbuf[len],
2964  s5r->wbuf_len - len);
2965  s5r->wbuf_len -= len;
2966  if (s5r->wbuf_len > 0)
2967  {
2968  /* not done writing */
2969  s5r->wtask =
2971  s5r->sock,
2972  &do_write, s5r);
2973  return;
2974  }
2975 
2976  /* we're done writing, continue with state machine! */
2977 
2978  switch (s5r->state)
2979  {
2980  case SOCKS5_INIT:
2981  GNUNET_assert (0);
2982  break;
2983 
2984  case SOCKS5_REQUEST:
2985  GNUNET_assert (NULL != s5r->rtask);
2986  break;
2987 
2988  case SOCKS5_DATA_TRANSFER:
2989  setup_data_transfer (s5r);
2990  return;
2991 
2993  cleanup_s5r (s5r);
2994  return;
2995 
2996  default:
2997  GNUNET_break (0);
2998  break;
2999  }
3000 }
ssize_t GNUNET_NETWORK_socket_send(const struct GNUNET_NETWORK_Handle *desc, const void *buffer, size_t length)
Send data (always non-blocking).
Definition: network.c:816
We&#39;re waiting to get the client hello.
struct GNUNET_SCHEDULER_Task * wtask
Client socket write task.
static void do_write(void *cls)
Write data from buffer to socks5 client, then continue with state machine.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
We&#39;re waiting to get the initial request.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_write_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *wfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1557
struct GNUNET_NETWORK_Handle * sock
The client socket.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
char wbuf[(256+32)]
Write buffer.
static void setup_data_transfer(struct Socks5Request *s5r)
We&#39;re done with the Socks5 protocol, now we need to pass the connection data through to the final des...
enum SocksPhase state
The socks state.
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct GNUNET_SCHEDULER_Task * rtask
Client socket read task.
Finish writing the write buffer, then clean up.
static void cleanup_s5r(struct Socks5Request *s5r)
Clean up s5r handles.
#define GNUNET_log(kind,...)
We&#39;re in transfer mode.
A structure for socks requests.
size_t wbuf_len
Number of bytes already in write buffer.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
Here is the call graph for this function:
Here is the caller graph for this function:

◆ signal_socks_failure()

static void signal_socks_failure ( struct Socks5Request s5r,
enum Socks5StatusCode  sc 
)
static

Return a server response message indicating a failure to the client.

Parameters
s5rrequest to return failure code for
scstatus code to return

Definition at line 3010 of file gnunet-gns-proxy.c.

References do_write(), GNUNET_SCHEDULER_add_write_net(), GNUNET_TIME_UNIT_FOREVER_REL, Socks5ServerResponseMessage::reply, sc, Socks5Request::sock, SOCKS5_WRITE_THEN_CLEANUP, SOCKS_VERSION_5, Socks5Request::state, Socks5ServerResponseMessage::version, Socks5Request::wbuf, Socks5Request::wbuf_len, and Socks5Request::wtask.

Referenced by do_s5r_read(), and handle_gns_result().

3012 {
3013  struct Socks5ServerResponseMessage *s_resp;
3014 
3015  s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3016  memset (s_resp, 0, sizeof(struct Socks5ServerResponseMessage));
3017  s_resp->version = SOCKS_VERSION_5;
3018  s_resp->reply = sc;
3020  if (NULL != s5r->wtask)
3021  s5r->wtask =
3023  s5r->sock,
3024  &do_write, s5r);
3025 }
uint8_t version
Should be SOCKS_VERSION_5.
struct GNUNET_SCHEDULER_Task * wtask
Client socket write task.
static void do_write(void *cls)
Write data from buffer to socks5 client, then continue with state machine.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_write_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *wfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1557
struct GNUNET_NETWORK_Handle * sock
The client socket.
uint8_t reply
Status code, an enum Socks5StatusCode
char wbuf[(256+32)]
Write buffer.
enum SocksPhase state
The socks state.
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
Finish writing the write buffer, then clean up.
static struct GNUNET_FS_SearchContext * sc
Definition: gnunet-search.c:37
Server response to client requests in Socks5 protocol.
#define SOCKS_VERSION_5
Which SOCKS version do we speak?
size_t wbuf_len
Number of bytes already in write buffer.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ signal_socks_success()

static void signal_socks_success ( struct Socks5Request s5r)
static

Return a server response message indicating success.

Parameters
s5rrequest to return success status message for

Definition at line 3034 of file gnunet-gns-proxy.c.

References Socks5ServerResponseMessage::addr_type, do_write(), GNUNET_SCHEDULER_add_write_net(), GNUNET_TIME_UNIT_FOREVER_REL, Socks5ServerResponseMessage::reply, Socks5ServerResponseMessage::reserved, Socks5Request::sock, SOCKS5_AT_IPV4, SOCKS5_STATUS_REQUEST_GRANTED, SOCKS_VERSION_5, Socks5ServerResponseMessage::version, Socks5Request::wbuf, Socks5Request::wbuf_len, and Socks5Request::wtask.

Referenced by do_s5r_read(), and handle_gns_result().

3035 {
3036  struct Socks5ServerResponseMessage *s_resp;
3037 
3038  s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3039  s_resp->version = SOCKS_VERSION_5;
3041  s_resp->reserved = 0;
3042  s_resp->addr_type = SOCKS5_AT_IPV4;
3043  /* zero out IPv4 address and port */
3044  memset (&s_resp[1],
3045  0,
3046  sizeof(struct in_addr) + sizeof(uint16_t));
3047  s5r->wbuf_len += sizeof(struct Socks5ServerResponseMessage)
3048  + sizeof(struct in_addr) + sizeof(uint16_t);
3049  if (NULL == s5r->wtask)
3050  s5r->wtask =
3052  s5r->sock,
3053  &do_write, s5r);
3054 }
uint8_t version
Should be SOCKS_VERSION_5.
uint8_t addr_type
Address type, an enum Socks5AddressType.
struct GNUNET_SCHEDULER_Task * wtask
Client socket write task.
static void do_write(void *cls)
Write data from buffer to socks5 client, then continue with state machine.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_write_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *wfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1557
struct GNUNET_NETWORK_Handle * sock
The client socket.
IPv4 address.
uint8_t reply
Status code, an enum Socks5StatusCode
char wbuf[(256+32)]
Write buffer.
uint8_t reserved
Always zero.
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
Server response to client requests in Socks5 protocol.
#define SOCKS_VERSION_5
Which SOCKS version do we speak?
size_t wbuf_len
Number of bytes already in write buffer.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_gns_result()

static void handle_gns_result ( void *  cls,
int  tld,
uint32_t  rd_count,
const struct GNUNET_GNSRECORD_Data rd 
)
static

Process GNS results for target domain.

Parameters
clsthe struct Socks5Request *
tldGNUNET_YES if this was a GNS TLD.
rd_countnumber of records returned
rdrecord data

Definition at line 3066 of file gnunet-gns-proxy.c.

References Socks5Request::dane_data, Socks5Request::dane_data_len, GNUNET_GNSRECORD_Data::data, GNUNET_GNSRECORD_Data::data_size, Socks5Request::destination_address, disable_v6, Socks5Request::gns_lookup, GNUNET_break, GNUNET_break_op, GNUNET_DNSPARSER_TYPE_A, GNUNET_DNSPARSER_TYPE_AAAA, GNUNET_DNSPARSER_TYPE_TLSA, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free_non_null, GNUNET_GNSRECORD_TYPE_BOX, GNUNET_GNSRECORD_TYPE_LEHO, GNUNET_GNSRECORD_TYPE_VPN, GNUNET_log, GNUNET_memcpy, GNUNET_memdup, GNUNET_NETWORK_test_pf(), GNUNET_NO, GNUNET_OK, GNUNET_strndup, GNUNET_YES, Socks5Request::is_gns, Socks5Request::is_tls, Socks5Request::leho, MAX_DANES, Socks5Request::num_danes, Socks5Request::port, GNUNET_GNSRECORD_BoxRecord::protocol, GNUNET_GNSRECORD_Data::record_type, GNUNET_GNSRECORD_BoxRecord::record_type, GNUNET_GNSRECORD_BoxRecord::service, signal_socks_failure(), signal_socks_success(), SOCKS5_DATA_TRANSFER, SOCKS5_STATUS_GENERAL_FAILURE, and Socks5Request::state.

Referenced by do_s5r_read().

3070 {
3071  struct Socks5Request *s5r = cls;
3072  const struct GNUNET_GNSRECORD_Data *r;
3073  int got_ip;
3074 
3075  s5r->gns_lookup = NULL;
3076  s5r->is_gns = tld;
3077  got_ip = GNUNET_NO;
3078  for (uint32_t i = 0; i < rd_count; i++)
3079  {
3080  r = &rd[i];
3081  switch (r->record_type)
3082  {
3084  {
3085  struct sockaddr_in *in;
3086 
3087  if (sizeof(struct in_addr) != r->data_size)
3088  {
3089  GNUNET_break_op (0);
3090  break;
3091  }
3092  if (GNUNET_YES == got_ip)
3093  break;
3094  if (GNUNET_OK !=
3095  GNUNET_NETWORK_test_pf (PF_INET))
3096  break;
3097  got_ip = GNUNET_YES;
3098  in = (struct sockaddr_in *) &s5r->destination_address;
3099  in->sin_family = AF_INET;
3100  GNUNET_memcpy (&in->sin_addr,
3101  r->data,
3102  r->data_size);
3103  in->sin_port = htons (s5r->port);
3104 #if HAVE_SOCKADDR_IN_SIN_LEN
3105  in->sin_len = sizeof(*in);
3106 #endif
3107  }
3108  break;
3109 
3111  {
3112  struct sockaddr_in6 *in;
3113 
3114  if (sizeof(struct in6_addr) != r->data_size)
3115  {
3116  GNUNET_break_op (0);
3117  break;
3118  }
3119  if (GNUNET_YES == got_ip)
3120  break;
3121  if (GNUNET_YES == disable_v6)
3122  break;
3123  if (GNUNET_OK !=
3124  GNUNET_NETWORK_test_pf (PF_INET6))
3125  break;
3126  /* FIXME: allow user to disable IPv6 per configuration option... */
3127  got_ip = GNUNET_YES;
3128  in = (struct sockaddr_in6 *) &s5r->destination_address;
3129  in->sin6_family = AF_INET6;
3130  GNUNET_memcpy (&in->sin6_addr,
3131  r->data,
3132  r->data_size);
3133  in->sin6_port = htons (s5r->port);
3134 #if HAVE_SOCKADDR_IN_SIN_LEN
3135  in->sin6_len = sizeof(*in);
3136 #endif
3137  }
3138  break;
3139 
3141  GNUNET_break (0); /* should have been translated within GNS */
3142  break;
3143 
3145  GNUNET_free_non_null (s5r->leho);
3146  s5r->leho = GNUNET_strndup (r->data,
3147  r->data_size);
3148  break;
3149 
3151  {
3152  const struct GNUNET_GNSRECORD_BoxRecord *box;
3153 
3154  if (r->data_size < sizeof(struct GNUNET_GNSRECORD_BoxRecord))
3155  {
3156  GNUNET_break_op (0);
3157  break;
3158  }
3159  box = r->data;
3160  if ((ntohl (box->record_type) != GNUNET_DNSPARSER_TYPE_TLSA) ||
3161  (ntohs (box->protocol) != IPPROTO_TCP) ||
3162  (ntohs (box->service) != s5r->port))
3163  break; /* BOX record does not apply */
3164  if (s5r->num_danes >= MAX_DANES)
3165  {
3166  GNUNET_break (0); /* MAX_DANES too small */
3167  break;
3168  }
3169  s5r->is_tls = GNUNET_YES; /* This should be TLS */
3170  s5r->dane_data_len[s5r->num_danes]
3171  = r->data_size - sizeof(struct GNUNET_GNSRECORD_BoxRecord);
3172  s5r->dane_data[s5r->num_danes]
3173  = GNUNET_memdup (&box[1],
3174  s5r->dane_data_len[s5r->num_danes]);
3175  s5r->num_danes++;
3176  break;
3177  }
3178 
3179  default:
3180  /* don't care */
3181  break;
3182  }
3183  }
3184  if ((GNUNET_YES != got_ip) &&
3185  (GNUNET_YES == tld))
3186  {
3188  "Name resolution failed to yield useful IP address.\n");
3189  signal_socks_failure (s5r,
3191  return;
3192  }
3193  s5r->state = SOCKS5_DATA_TRANSFER;
3194  signal_socks_success (s5r);
3195 }
uint16_t service
Service of the boxed record (aka port number), in NBO.
Record type used to box up SRV and TLSA records.
char * dane_data[32+1]
Payload of the DANE records encountered.
int dane_data_len[32+1]
Number of bytes in dane_data.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define MAX_DANES
Maximum number of DANE records we support per domain name (and port and protocol).
size_t data_size
Number of bytes in data.
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
#define GNUNET_GNSRECORD_TYPE_BOX
Record type for a boxed record (see TLSA/SRV handling in GNS).
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
#define GNUNET_GNSRECORD_TYPE_VPN
Record type for VPN resolution.
static void signal_socks_failure(struct Socks5Request *s5r, enum Socks5StatusCode sc)
Return a server response message indicating a failure to the client.
const void * data
Binary value stored in the DNS record.
unsigned int num_danes
Number of entries used in dane_data_len and dane_data.
struct GNUNET_GNS_LookupWithTldRequest * gns_lookup
Handle to GNS lookup, during SOCKS5_RESOLVING phase.
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
enum SocksPhase state
The socks state.
uint16_t protocol
Protocol of the boxed record (6 = TCP, 17 = UDP, etc.).
uint16_t port
Desired destination port.
struct sockaddr_storage destination_address
Once known, what&#39;s the target address for the connection?
uint32_t record_type
GNS record type of the boxed record.
#define GNUNET_DNSPARSER_TYPE_TLSA
#define GNUNET_GNSRECORD_TYPE_LEHO
Record type for GNS legacy hostnames ("LEHO").
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
int is_gns
Was the hostname resolved via GNS?
uint32_t record_type
Type of the GNS/DNS record.
char * leho
DNS Legacy Host Name as given by GNS, NULL if not given.
#define GNUNET_DNSPARSER_TYPE_AAAA
#define GNUNET_log(kind,...)
int is_tls
This is (probably) a TLS connection.
static void signal_socks_success(struct Socks5Request *s5r)
Return a server response message indicating success.
#define GNUNET_YES
Definition: gnunet_common.h:77
We&#39;re in transfer mode.
A structure for socks requests.
#define GNUNET_DNSPARSER_TYPE_A
int GNUNET_NETWORK_test_pf(int pf)
Test if the given protocol family is supported by this system.
Definition: network.c:85
static int disable_v6
Disable IPv6.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_from_s5r_rbuf()

static void clear_from_s5r_rbuf ( struct Socks5Request s5r,
size_t  len 
)
static

Remove the first len bytes from the beginning of the read buffer.

Parameters
s5rthe handle clear the read buffer for
lennumber of bytes in read buffer to advance

Definition at line 3205 of file gnunet-gns-proxy.c.

References GNUNET_assert, len, Socks5Request::rbuf, and Socks5Request::rbuf_len.

Referenced by do_s5r_read().

3207 {
3208  GNUNET_assert (len <= s5r->rbuf_len);
3209  memmove (s5r->rbuf,
3210  &s5r->rbuf[len],
3211  s5r->rbuf_len - len);
3212  s5r->rbuf_len -= len;
3213 }
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
char rbuf[(256+32)]
Read buffer.
size_t rbuf_len
Number of bytes already in read buffer.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
Here is the caller graph for this function:

◆ do_s5r_read()

static void do_s5r_read ( void *  cls)
static

Read data from incoming Socks5 connection.

Parameters
clsthe closure with the struct Socks5Request

Definition at line 3222 of file gnunet-gns-proxy.c.

References _, Socks5ClientRequestMessage::addr_type, Socks5ServerHelloMessage::auth_method, cleanup_s5r(), clear_from_s5r_rbuf(), Socks5ClientRequestMessage::command, Socks5Request::destination_address, do_write(), Socks5Request::domain, Socks5Request::gns_lookup, GNUNET_assert, GNUNET_break_op, GNUNET_DNSPARSER_TYPE_A, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_GNS_lookup_with_tld(), GNUNET_log, GNUNET_NETWORK_fdset_isset(), GNUNET_NETWORK_socket_recv(), GNUNET_NO, GNUNET_SCHEDULER_add_read_net(), GNUNET_SCHEDULER_add_write_net(), GNUNET_SCHEDULER_cancel(), GNUNET_SCHEDULER_get_task_context(), GNUNET_strndup, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, handle_gns_result(), HTTPS_PORT, Socks5Request::is_tls, Socks5ClientHelloMessage::num_auth_methods, Socks5Request::port, port, Socks5Request::rbuf, Socks5Request::rbuf_len, GNUNET_SCHEDULER_TaskContext::read_ready, Socks5Request::rtask, signal_socks_failure(), signal_socks_success(), Socks5Request::sock, SOCKS5_AT_DOMAINNAME, SOCKS5_AT_IPV4, SOCKS5_AT_IPV6, SOCKS5_CMD_TCP_STREAM, SOCKS5_DATA_TRANSFER, SOCKS5_INIT, SOCKS5_REQUEST, SOCKS5_RESOLVING, SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED, SOCKS5_STATUS_COMMAND_NOT_SUPPORTED, SOCKS5_STATUS_GENERAL_FAILURE, SOCKS_AUTH_NONE, SOCKS_VERSION_5, Socks5Request::state, tc, Socks5ClientHelloMessage::version, Socks5ServerHelloMessage::version, Socks5Request::wbuf, Socks5Request::wbuf_len, and Socks5Request::wtask.

Referenced by do_accept().

3223 {
3224  struct Socks5Request *s5r = cls;
3225  const struct Socks5ClientHelloMessage *c_hello;
3226  struct Socks5ServerHelloMessage *s_hello;
3227  const struct Socks5ClientRequestMessage *c_req;
3228  ssize_t rlen;
3229  size_t alen;
3230  const struct GNUNET_SCHEDULER_TaskContext *tc;
3231 
3232  s5r->rtask = NULL;
3234  if ((NULL != tc->read_ready) &&
3236  s5r->sock)))
3237  {
3238  rlen = GNUNET_NETWORK_socket_recv (s5r->sock,
3239  &s5r->rbuf[s5r->rbuf_len],
3240  sizeof(s5r->rbuf) - s5r->rbuf_len);
3241  if (rlen <= 0)
3242  {
3244  "socks5 client disconnected.\n");
3245  cleanup_s5r (s5r);
3246  return;
3247  }
3248  s5r->rbuf_len += rlen;
3249  }
3251  s5r->sock,
3252  &do_s5r_read, s5r);
3254  "Processing %zu bytes of socks data in state %d\n",
3255  s5r->rbuf_len,
3256  s5r->state);
3257  switch (s5r->state)
3258  {
3259  case SOCKS5_INIT:
3260  c_hello = (const struct Socks5ClientHelloMessage*) &s5r->rbuf;
3261  if ((s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)) ||
3262  (s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)
3263  + c_hello->num_auth_methods))
3264  return; /* need more data */
3265  if (SOCKS_VERSION_5 != c_hello->version)
3266  {
3268  _ ("Unsupported socks version %d\n"),
3269  (int) c_hello->version);
3270  cleanup_s5r (s5r);
3271  return;
3272  }
3273  clear_from_s5r_rbuf (s5r,
3274  sizeof(struct Socks5ClientHelloMessage)
3275  + c_hello->num_auth_methods);
3276  GNUNET_assert (0 == s5r->wbuf_len);
3277  s_hello = (struct Socks5ServerHelloMessage *) &s5r->wbuf;
3278  s5r->wbuf_len = sizeof(struct Socks5ServerHelloMessage);
3279  s_hello->version = SOCKS_VERSION_5;
3280  s_hello->auth_method = SOCKS_AUTH_NONE;
3281  GNUNET_assert (NULL == s5r->wtask);
3283  s5r->sock,
3284  &do_write, s5r);
3285  s5r->state = SOCKS5_REQUEST;
3286  return;
3287 
3288  case SOCKS5_REQUEST:
3289  c_req = (const struct Socks5ClientRequestMessage *) &s5r->rbuf;
3290  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage))
3291  return;
3292  switch (c_req->command)
3293  {
3294  case SOCKS5_CMD_TCP_STREAM:
3295  /* handled below */
3296  break;
3297 
3298  default:
3300  _ ("Unsupported socks command %d\n"),
3301  (int) c_req->command);
3302  signal_socks_failure (s5r,
3304  return;
3305  }
3306  switch (c_req->addr_type)
3307  {
3308  case SOCKS5_AT_IPV4:
3309  {
3310  const struct in_addr *v4 = (const struct in_addr *) &c_req[1];
3311  const uint16_t *port = (const uint16_t *) &v4[1];
3312  struct sockaddr_in *in;
3313 
3314  s5r->port = ntohs (*port);
3315  alen = sizeof(struct in_addr);
3316  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3317  + alen + sizeof(uint16_t))
3318  return; /* need more data */
3319  in = (struct sockaddr_in *) &s5r->destination_address;
3320  in->sin_family = AF_INET;
3321  in->sin_addr = *v4;
3322  in->sin_port = *port;
3323 #if HAVE_SOCKADDR_IN_SIN_LEN
3324  in->sin_len = sizeof(*in);
3325 #endif
3326  s5r->state = SOCKS5_DATA_TRANSFER;
3327  }
3328  break;
3329 
3330  case SOCKS5_AT_IPV6:
3331  {
3332  const struct in6_addr *v6 = (const struct in6_addr *) &c_req[1];
3333  const uint16_t *port = (const uint16_t *) &v6[1];
3334  struct sockaddr_in6 *in;
3335 
3336  s5r->port = ntohs (*port);
3337  alen = sizeof(struct in6_addr);
3338  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3339  + alen + sizeof(uint16_t))
3340  return; /* need more data */
3341  in = (struct sockaddr_in6 *) &s5r->destination_address;
3342  in->sin6_family = AF_INET6;
3343  in->sin6_addr = *v6;
3344  in->sin6_port = *port;
3345 #if HAVE_SOCKADDR_IN_SIN_LEN
3346  in->sin6_len = sizeof(*in);
3347 #endif
3348  s5r->state = SOCKS5_DATA_TRANSFER;
3349  }
3350  break;
3351 
3352  case SOCKS5_AT_DOMAINNAME:
3353  {
3354  const uint8_t *dom_len;
3355  const char *dom_name;
3356  const uint16_t *port;
3357 
3358  dom_len = (const uint8_t *) &c_req[1];
3359  alen = *dom_len + 1;
3360  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3361  + alen + sizeof(uint16_t))
3362  return; /* need more data */
3363  dom_name = (const char *) &dom_len[1];
3364  port = (const uint16_t*) &dom_name[*dom_len];
3365  s5r->domain = GNUNET_strndup (dom_name,
3366  *dom_len);
3368  "Requested connection is to %s:%d\n",
3369  // (HTTPS_PORT == s5r->port) ? "s" : "",
3370  s5r->domain,
3371  ntohs (*port));
3372  s5r->state = SOCKS5_RESOLVING;
3373  s5r->port = ntohs (*port);
3374  s5r->is_tls = (HTTPS_PORT == s5r->port) ? GNUNET_YES : GNUNET_NO;
3376  s5r->domain,
3378  GNUNET_NO /* only cached */,
3380  s5r);
3381  break;
3382  }
3383 
3384  default:
3386  _ ("Unsupported socks address type %d\n"),
3387  (int) c_req->addr_type);
3388  signal_socks_failure (s5r,
3390  return;
3391  }
3392  clear_from_s5r_rbuf (s5r,
3393  sizeof(struct Socks5ClientRequestMessage)
3394  + alen + sizeof(uint16_t));
3395  if (0 != s5r->rbuf_len)
3396  {
3397  /* read more bytes than healthy, why did the client send more!? */
3398  GNUNET_break_op (0);
3399  signal_socks_failure (s5r,
3401  return;
3402  }
3403  if (SOCKS5_DATA_TRANSFER == s5r->state)
3404  {
3405  /* if we are not waiting for GNS resolution, signal success */
3406  signal_socks_success (s5r);
3407  }
3408  /* We are done reading right now */
3410  s5r->rtask = NULL;
3411  return;
3412 
3413  case SOCKS5_RESOLVING:
3414  GNUNET_assert (0);
3415  return;
3416 
3417  case SOCKS5_DATA_TRANSFER:
3418  GNUNET_assert (0);
3419  return;
3420 
3421  default:
3422  GNUNET_assert (0);
3423  return;
3424  }
3425 }
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:747
uint8_t num_auth_methods
How many authentication methods does the client support.
We&#39;re waiting to get the client hello.
Context information passed to each scheduler task.
struct GNUNET_SCHEDULER_Task * wtask
Client socket write task.
ssize_t GNUNET_NETWORK_socket_recv(const struct GNUNET_NETWORK_Handle *desc, void *buffer, size_t length)
Read data from a connected socket (always non-blocking).
Definition: network.c:787
#define HTTPS_PORT
Port for HTTPS.
static void do_write(void *cls)
Write data from buffer to socks5 client, then continue with state machine.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
char rbuf[(256+32)]
Read buffer.
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:418
struct GNUNET_GNS_LookupWithTldRequest * GNUNET_GNS_lookup_with_tld(struct GNUNET_GNS_Handle *handle, const char *name, uint32_t type, enum GNUNET_GNS_LocalOptions options, GNUNET_GNS_LookupResultProcessor2 proc, void *proc_cls)
Perform an asynchronous lookup operation on the GNS, determining the zone using the TLD of the given ...
Definition: gns_tld_api.c:241
Server hello in Socks5 protocol.
We&#39;re waiting to get the initial request.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_write_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *wfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1557
struct GNUNET_NETWORK_Handle * sock
The client socket.
#define GNUNET_NO
Definition: gnunet_common.h:78
IPv4 address.
const struct GNUNET_NETWORK_FDSet * read_ready
Set of file descriptors ready for reading; note that additional bits may be set that were not in the ...
static void do_s5r_read(void *cls)
Read data from incoming Socks5 connection.
#define SOCKS_AUTH_NONE
Flag to set for &#39;no authentication&#39;.
size_t rbuf_len
Number of bytes already in read buffer.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
static uint16_t port
The port the proxy is running on (default 7777)
static void signal_socks_failure(struct Socks5Request *s5r, enum Socks5StatusCode sc)
Return a server response message indicating a failure to the client.
char wbuf[(256+32)]
Write buffer.
Establish TCP/IP stream.
static struct GNUNET_GNS_Handle * gns_handle
Handle to the GNS service.
Client hello in Socks5 protocol.
struct GNUNET_GNS_LookupWithTldRequest * gns_lookup
Handle to GNS lookup, during SOCKS5_RESOLVING phase.
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
enum SocksPhase state
The socks state.
uint8_t auth_method
Chosen authentication method, for us always SOCKS_AUTH_NONE, which skips the authentication step...
char * domain
the domain name to server (only important for TLS)
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct GNUNET_SCHEDULER_Task * rtask
Client socket read task.
uint16_t port
Desired destination port.
static void cleanup_s5r(struct Socks5Request *s5r)
Clean up s5r handles.
struct sockaddr_storage destination_address
Once known, what&#39;s the target address for the connection?
uint8_t version
Should be SOCKS_VERSION_5.
uint8_t version
Should be SOCKS_VERSION_5.
Client socks request in Socks5 protocol.
IPv6 address.
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
#define GNUNET_log(kind,...)
int is_tls
This is (probably) a TLS connection.
static void signal_socks_success(struct Socks5Request *s5r)
Return a server response message indicating success.
#define GNUNET_YES
Definition: gnunet_common.h:77
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1486
static void clear_from_s5r_rbuf(struct Socks5Request *s5r, size_t len)
Remove the first len bytes from the beginning of the read buffer.
static void handle_gns_result(void *cls, int tld, uint32_t rd_count, const struct GNUNET_GNSRECORD_Data *rd)
Process GNS results for target domain.
We are currently resolving the destination.
We&#39;re in transfer mode.
int GNUNET_NETWORK_fdset_isset(const struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_NETWORK_Handle *desc)
Check whether a socket is part of the fd set.
Definition: network.c:1029
A structure for socks requests.
#define SOCKS_VERSION_5
Which SOCKS version do we speak?
#define GNUNET_DNSPARSER_TYPE_A
uint8_t command
Command code, we only uspport SOCKS5_CMD_TCP_STREAM.
size_t wbuf_len
Number of bytes already in write buffer.
uint8_t addr_type
Address type, an enum Socks5AddressType.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:966
Here is the call graph for this function:
Here is the caller graph for this function:

◆ do_accept()

static void do_accept ( void *  cls)
static

Accept new incoming connections.

Parameters
clsthe closure with the lsock4 or lsock6
tcthe scheduler context

Definition at line 3435 of file gnunet-gns-proxy.c.

References do_s5r_read(), GNUNET_assert, GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_log_strerror, GNUNET_NETWORK_socket_accept(), GNUNET_new, GNUNET_SCHEDULER_add_read_net(), GNUNET_TIME_UNIT_FOREVER_REL, Socks5Request::rtask, Socks5Request::sock, SOCKS5_INIT, and Socks5Request::state.

Referenced by run().

3436 {
3437  struct GNUNET_NETWORK_Handle *lsock = cls;
3438  struct GNUNET_NETWORK_Handle *s;
3439  struct Socks5Request *s5r;
3440 
3441  GNUNET_assert (NULL != lsock);
3442  if (lsock == lsock4)
3444  lsock,
3445  &do_accept,
3446  lsock);
3447  else if (lsock == lsock6)
3449  lsock,
3450  &do_accept,
3451  lsock);
3452  else
3453  GNUNET_assert (0);
3454  s = GNUNET_NETWORK_socket_accept (lsock,
3455  NULL,
3456  NULL);
3457  if (NULL == s)
3458  {
3460  "accept");
3461  return;
3462  }
3464  "Got an inbound connection, waiting for data\n");
3465  s5r = GNUNET_new (struct Socks5Request);
3467  s5r_tail,
3468  s5r);
3469  s5r->sock = s;
3470  s5r->state = SOCKS5_INIT;
3472  s5r->sock,
3473  &do_s5r_read,
3474  s5r);
3475 }
static struct Socks5Request * s5r_tail
DLL of active socks requests.
static struct GNUNET_SCHEDULER_Task * ltask4
The listen task ID for IPv4.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
We&#39;re waiting to get the client hello.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
struct GNUNET_NETWORK_Handle * sock
The client socket.
static struct GNUNET_SCHEDULER_Task * ltask6
The listen task ID for IPv6.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
static void do_s5r_read(void *cls)
Read data from incoming Socks5 connection.
static struct GNUNET_NETWORK_Handle * lsock6
The listen socket of the proxy for IPv6.
static struct GNUNET_NETWORK_Handle * lsock4
The listen socket of the proxy for IPv4.
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_accept(const struct GNUNET_NETWORK_Handle *desc, struct sockaddr *address, socklen_t *address_len)
Accept a new connection on a socket.
Definition: network.c:430
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
static void do_accept(void *cls)
Accept new incoming connections.
enum SocksPhase state
The socks state.
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct GNUNET_SCHEDULER_Task * rtask
Client socket read task.
static struct Socks5Request * s5r_head
DLL of active socks requests.
#define GNUNET_log(kind,...)
handle to a socket
Definition: network.c:52
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1486
A structure for socks requests.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ do_shutdown()

static void do_shutdown ( void *  cls)
static

Task run on shutdown.

Parameters
clsclosure

Definition at line 3487 of file gnunet-gns-proxy.c.

References ProxyCA::cert, cleanup_s5r(), curl_multi, GNUNET_ERROR_TYPE_INFO, GNUNET_GNS_disconnect(), GNUNET_log, GNUNET_NETWORK_socket_close(), GNUNET_NO, GNUNET_SCHEDULER_cancel(), ProxyCA::key, kill_httpd(), Socks5Request::next, and proxy_ca.

Referenced by run().

3488 {
3490  "Shutting down...\n");
3491  /* MHD requires resuming before destroying the daemons */
3492  for (struct Socks5Request *s5r = s5r_head;
3493  NULL != s5r;
3494  s5r = s5r->next)
3495  {
3496  if (s5r->suspended)
3497  {
3498  s5r->suspended = GNUNET_NO;
3499  MHD_resume_connection (s5r->con);
3500  }
3501  }
3502  while (NULL != mhd_httpd_head)
3504  while (NULL != s5r_head)
3506  if (NULL != lsock4)
3507  {
3509  lsock4 = NULL;
3510  }
3511  if (NULL != lsock6)
3512  {
3514  lsock6 = NULL;
3515  }
3516  if (NULL != curl_multi)
3517  {
3518  curl_multi_cleanup (curl_multi);
3519  curl_multi = NULL;
3520  }
3521  if (NULL != gns_handle)
3522  {
3524  gns_handle = NULL;
3525  }
3526  if (NULL != curl_download_task)
3527  {
3529  curl_download_task = NULL;
3530  }
3531  if (NULL != ltask4)
3532  {
3534  ltask4 = NULL;
3535  }
3536  if (NULL != ltask6)
3537  {
3539  ltask6 = NULL;
3540  }
3541  gnutls_x509_crt_deinit (proxy_ca.cert);
3542  gnutls_x509_privkey_deinit (proxy_ca.key);
3543  gnutls_global_deinit ();
3544 }
static struct GNUNET_SCHEDULER_Task * ltask4
The listen task ID for IPv4.
static struct GNUNET_SCHEDULER_Task * ltask6
The listen task ID for IPv6.
#define GNUNET_NO
Definition: gnunet_common.h:78
static struct ProxyCA proxy_ca
The CA for X.509 certificate generation.
static struct GNUNET_NETWORK_Handle * lsock6
The listen socket of the proxy for IPv6.
static struct GNUNET_NETWORK_Handle * lsock4
The listen socket of the proxy for IPv4.
static struct GNUNET_GNS_Handle * gns_handle
Handle to the GNS service.
void GNUNET_GNS_disconnect(struct GNUNET_GNS_Handle *handle)
Shutdown connection with the GNS service.
Definition: gns_api.c:284
struct Socks5Request * next
DLL.
static struct Socks5Request * s5r_head
DLL of active socks requests.
static void cleanup_s5r(struct Socks5Request *s5r)
Clean up s5r handles.
static struct GNUNET_SCHEDULER_Task * curl_download_task
The cURL download task (curl multi API).
static void kill_httpd(struct MhdHttpList *hd)
Kill the given MHD daemon.
gnutls_x509_privkey_t key
The private key.
static struct MhdHttpList * mhd_httpd_head
DLL for http/https daemons.
#define GNUNET_log(kind,...)
gnutls_x509_crt_t cert
The certificate.
A structure for socks requests.
static CURLM * curl_multi
The cURL multi handle.
int GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:560
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:966
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bind_v4()

static struct GNUNET_NETWORK_Handle* bind_v4 ( )
static

Create an IPv4 listen socket bound to our port.

Returns
NULL on error

Definition at line 3553 of file gnunet-gns-proxy.c.

References address, GNUNET_NETWORK_socket_bind(), GNUNET_NETWORK_socket_close(), GNUNET_NETWORK_socket_create(), GNUNET_OK, ls, and port.

Referenced by run().

3554 {
3555  struct GNUNET_NETWORK_Handle *ls;
3556  struct sockaddr_in sa4;
3557  int eno;
3558 
3559  memset (&sa4, 0, sizeof(sa4));
3560  sa4.sin_family = AF_INET;
3561  sa4.sin_port = htons (port);
3562  sa4.sin_addr.s_addr = address;
3563 #if HAVE_SOCKADDR_IN_SIN_LEN
3564  sa4.sin_len = sizeof(sa4);
3565 #endif
3566  ls = GNUNET_NETWORK_socket_create (AF_INET,
3567  SOCK_STREAM,
3568  0);
3569  if (NULL == ls)
3570  return NULL;
3571  if (GNUNET_OK !=
3573  (const struct sockaddr *) &sa4,
3574  sizeof(sa4)))
3575  {
3576  eno = errno;
3578  errno = eno;
3579  return NULL;
3580  }
3581  return ls;
3582 }
int GNUNET_NETWORK_socket_bind(struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len)
Bind a socket to a particular address.
Definition: network.c:485
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
static in_addr_t address
The address to bind to.
static uint16_t port
The port the proxy is running on (default 7777)
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition: gnunet-nat.c:85
handle to a socket
Definition: network.c:52
int GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:560
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:912
Here is the call graph for this function:
Here is the caller graph for this function:

◆ bind_v6()

static struct GNUNET_NETWORK_Handle* bind_v6 ( )
static

Create an IPv6 listen socket bound to our port.

Returns
NULL on error

Definition at line 3591 of file gnunet-gns-proxy.c.

References address6, GNUNET_NETWORK_socket_bind(), GNUNET_NETWORK_socket_close(), GNUNET_NETWORK_socket_create(), GNUNET_OK, ls, and port.

Referenced by run().

3592 {
3593  struct GNUNET_NETWORK_Handle *ls;
3594  struct sockaddr_in6 sa6;
3595  int eno;
3596 
3597  memset (&sa6, 0, sizeof(sa6));
3598  sa6.sin6_family = AF_INET6;
3599  sa6.sin6_port = htons (port);
3600  sa6.sin6_addr = address6;
3601 #if HAVE_SOCKADDR_IN_SIN_LEN
3602  sa6.sin6_len = sizeof(sa6);
3603 #endif
3604  ls = GNUNET_NETWORK_socket_create (AF_INET6,
3605  SOCK_STREAM,
3606  0);
3607  if (NULL == ls)
3608  return NULL;
3609  if (GNUNET_OK !=
3611  (const struct sockaddr *) &sa6,
3612  sizeof(sa6)))
3613  {
3614  eno = errno;
3616  errno = eno;
3617  return NULL;
3618  }
3619  return ls;
3620 }
int GNUNET_NETWORK_socket_bind(struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len)
Bind a socket to a particular address.
Definition: network.c:485
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
static uint16_t port
The port the proxy is running on (default 7777)
static struct in6_addr address6
The IPv6 address to bind to.
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition: gnunet-nat.c:85
handle to a socket
Definition: network.c:52
int GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:560
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:912
Here is the call graph for this function:
Here is the caller graph for this function:

◆ run()

static void run ( void *  cls,
char *const *  args,
const char *  cfgfile,
const struct GNUNET_CONFIGURATION_Handle c 
)
static

Main function that will be run.

Parameters
clsclosure
argsremaining command-line arguments
cfgfilename of the configuration file used (for saving, can be NULL!)
cconfiguration

Definition at line 3632 of file gnunet-gns-proxy.c.

References _, address, address6, bind_v4(), bind_v6(), cafile_opt, ProxyCA::cert, create_response(), curl_multi, MhdHttpList::daemon, do_accept(), do_shutdown(), GNUNET_CONFIGURATION_get_value_filename(), GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_free, GNUNET_free_non_null, GNUNET_GNS_connect(), GNUNET_log, GNUNET_log_config_missing(), GNUNET_log_strerror, GNUNET_NETWORK_socket_close(), GNUNET_NETWORK_socket_listen(), GNUNET_new, GNUNET_OK, GNUNET_SCHEDULER_add_read_net(), GNUNET_SCHEDULER_add_shutdown(), GNUNET_SCHEDULER_shutdown(), GNUNET_TIME_UNIT_FOREVER_REL, ProxyCA::key, load_cert_from_file(), load_key_from_file(), mhd_completed_cb(), mhd_connection_cb(), mhd_log_callback(), port, and proxy_ca.

Referenced by main().

3636 {
3637  char*cafile_cfg = NULL;
3638  char*cafile;
3639  char*addr_str;
3640  struct MhdHttpList *hd;
3641 
3642  cfg = c;
3643 
3644  /* Get address to bind to */
3646  "BIND_TO",
3647  &addr_str))
3648  {
3649  // No address specified
3651  "Don't know what to bind to...\n");
3652  GNUNET_free (addr_str);
3654  return;
3655  }
3656  if (1 != inet_pton (AF_INET, addr_str, &address))
3657  {
3659  "Unable to parse address %s\n",
3660  addr_str);
3661  GNUNET_free (addr_str);
3663  return;
3664  }
3665  GNUNET_free (addr_str);
3666  /* Get address to bind to */
3668  "BIND_TO6",
3669  &addr_str))
3670  {
3671  // No address specified
3673  "Don't know what to bind6 to...\n");
3674  GNUNET_free (addr_str);
3676  return;
3677  }
3678  if (1 != inet_pton (AF_INET6, addr_str, &address6))
3679  {
3681  "Unable to parse IPv6 address %s\n",
3682  addr_str);
3683  GNUNET_free (addr_str);
3685  return;
3686  }
3687  GNUNET_free (addr_str);
3688 
3689  if (NULL == (curl_multi = curl_multi_init ()))
3690  {
3692  "Failed to create cURL multi handle!\n");
3693  return;
3694  }
3695  cafile = cafile_opt;
3696  if (NULL == cafile)
3697  {
3698  if (GNUNET_OK !=
3700  "gns-proxy",
3701  "PROXY_CACERT",
3702  &cafile_cfg))
3703  {
3705  "gns-proxy",
3706  "PROXY_CACERT");
3707  return;
3708  }
3709  cafile = cafile_cfg;
3710  }
3712  "Using `%s' as CA\n",
3713  cafile);
3714 
3715  gnutls_global_init ();
3716  gnutls_x509_crt_init (&proxy_ca.cert);
3717  gnutls_x509_privkey_init (&proxy_ca.key);
3718 
3719  if ((GNUNET_OK !=
3721  cafile)) ||
3722  (GNUNET_OK !=
3724  cafile)))
3725  {
3727  _ ("Failed to load X.509 key and certificate from `%s'\n"),
3728  cafile);
3729  gnutls_x509_crt_deinit (proxy_ca.cert);
3730  gnutls_x509_privkey_deinit (proxy_ca.key);
3731  gnutls_global_deinit ();
3732  GNUNET_free_non_null (cafile_cfg);
3733  return;
3734  }
3735  GNUNET_free_non_null (cafile_cfg);
3736  if (NULL == (gns_handle = GNUNET_GNS_connect (cfg)))
3737  {
3739  "Unable to connect to GNS!\n");
3740  gnutls_x509_crt_deinit (proxy_ca.cert);
3741  gnutls_x509_privkey_deinit (proxy_ca.key);
3742  gnutls_global_deinit ();
3743  return;
3744  }
3746  NULL);
3747 
3748  /* Open listen socket for socks proxy */
3749  lsock6 = bind_v6 ();
3750  if (NULL == lsock6)
3751  {
3753  "bind");
3754  }
3755  else
3756  {
3757  if (GNUNET_OK !=
3759  5))
3760  {
3762  "listen");
3764  lsock6 = NULL;
3765  }
3766  else
3767  {
3769  lsock6,
3770  &do_accept,
3771  lsock6);
3772  }
3773  }
3774  lsock4 = bind_v4 ();
3775  if (NULL == lsock4)
3776  {
3778  "bind");
3779  }
3780  else
3781  {
3782  if (GNUNET_OK !=
3784  5))
3785  {
3787  "listen");
3789  lsock4 = NULL;
3790  }
3791  else
3792  {
3794  lsock4,
3795  &do_accept,
3796  lsock4);
3797  }
3798  }
3799  if ((NULL == lsock4) &&
3800  (NULL == lsock6))
3801  {
3803  return;
3804  }
3805  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
3806  {
3808  "cURL global init failed!\n");
3810  return;
3811  }
3813  "Proxy listens on port %u\n",
3814  (unsigned int)