GNUnet  0.10.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   GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
 After how long do we clean up unused MHD TLS instances? More...
 
#define HTTP_HANDSHAKE_TIMEOUT   GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 15)
 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 52 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 58 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 64 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 70 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 77 of file gnunet-gns-proxy.c.

◆ HTTP_PORT

#define HTTP_PORT   80

Port for plaintext HTTP.

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

◆ HTTPS_PORT

#define HTTPS_PORT   443

Port for HTTPS.

Definition at line 87 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 92 of file gnunet-gns-proxy.c.

Referenced by load_file().

◆ MHD_CACHE_TIMEOUT

#define MHD_CACHE_TIMEOUT   GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)

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

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

Referenced by schedule_httpd().

◆ HTTP_HANDSHAKE_TIMEOUT

#define HTTP_HANDSHAKE_TIMEOUT   GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 15)

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 113 of file gnunet-gns-proxy.c.

◆ SOCKS_VERSION_5

#define SOCKS_VERSION_5   0x05

Which SOCKS version do we speak?

Definition at line 127 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 132 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 138 of file gnunet-gns-proxy.c.

138  {
143 
148 
153 };
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 159 of file gnunet-gns-proxy.c.

159  {
163  SOCKS5_AT_IPV4 = 1,
164 
169 
173  SOCKS5_AT_IPV6 = 4
174 };
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 180 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 375 of file gnunet-gns-proxy.c.

375  {
379  SOCKS5_INIT,
380 
385 
390 
395 
400 
405 
410 
415 
420 
425 };
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 2574 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().

2575 {
2576  if (NULL != hd->httpd_task)
2579  hd);
2580 }
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:1264
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:956
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 763 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().

764 {
766  "Cleaning up socks request\n");
767  if (NULL != s5r->curl)
768  {
770  "Cleaning up cURL handle\n");
771  curl_multi_remove_handle(curl_multi,
772  s5r->curl);
773  curl_easy_cleanup(s5r->curl);
774  s5r->curl = NULL;
775  }
776  if (s5r->suspended)
777  {
778  s5r->suspended = GNUNET_NO;
779  MHD_resume_connection(s5r->con);
780  }
781  curl_slist_free_all(s5r->headers);
782  if (NULL != s5r->hosts)
783  {
784  curl_slist_free_all(s5r->hosts);
785  }
786  if ((NULL != s5r->response) &&
788  {
789  MHD_destroy_response(s5r->response);
790  s5r->response = NULL;
791  }
792  if (NULL != s5r->rtask)
793  {
795  s5r->rtask = NULL;
796  }
797  if (NULL != s5r->timeout_task)
798  {
800  s5r->timeout_task = NULL;
801  }
802  if (NULL != s5r->wtask)
803  {
805  s5r->wtask = NULL;
806  }
807  if (NULL != s5r->gns_lookup)
808  {
810  s5r->gns_lookup = NULL;
811  }
812  if (NULL != s5r->sock)
813  {
814  if (SOCKS5_SOCKET_WITH_MHD <= s5r->state)
816  else
818  s5r->sock = NULL;
819  }
821  s5r_tail,
822  s5r);
826  for (unsigned int i = 0; i < s5r->num_danes; i++)
827  GNUNET_free(s5r->dane_data[i]);
828  GNUNET_free(s5r);
829 }
#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:328
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:610
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:548
#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:956
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 1556 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().

1557 {
1558  CURLMcode mret;
1559  fd_set rs;
1560  fd_set ws;
1561  fd_set es;
1562  int max;
1563  struct GNUNET_NETWORK_FDSet *grs;
1564  struct GNUNET_NETWORK_FDSet *gws;
1565  long to;
1566  struct GNUNET_TIME_Relative rtime;
1567 
1569  "Scheduling CURL interaction\n");
1570  if (NULL != curl_download_task)
1571  {
1573  curl_download_task = NULL;
1574  }
1575  max = -1;
1576  FD_ZERO(&rs);
1577  FD_ZERO(&ws);
1578  FD_ZERO(&es);
1579  if (CURLM_OK != (mret = curl_multi_fdset(curl_multi,
1580  &rs,
1581  &ws,
1582  &es,
1583  &max)))
1584  {
1586  "%s failed at %s:%d: `%s'\n",
1587  "curl_multi_fdset", __FILE__, __LINE__,
1588  curl_multi_strerror(mret));
1589  return;
1590  }
1591  to = -1;
1592  GNUNET_break(CURLM_OK ==
1593  curl_multi_timeout(curl_multi,
1594  &to));
1595  if (-1 == to)
1597  else
1599  to);
1600  if (-1 != max)
1601  {
1605  &rs,
1606  max + 1);
1608  &ws,
1609  max + 1);
1611  rtime,
1612  grs,
1613  gws,
1615  curl_multi);
1618  }
1619  else
1620  {
1623  curl_multi);
1624  }
1625 }
#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:1108
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1254
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:1237
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1238
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:1784
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:440
#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:956
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 850 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().

854 {
855  struct Socks5Request *s5r = cls;
856  size_t bytes_to_copy;
857 
858  if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
860  {
861  /* we're still not done with the upload, do not yet
862  start the download, the IO buffer is still full
863  with upload data. */
865  "Pausing MHD download %s%s, not yet ready for download\n",
866  s5r->domain,
867  s5r->url);
868  return 0; /* not yet ready for data download */
869  }
870  bytes_to_copy = GNUNET_MIN(max,
871  s5r->io_len);
872  if ((0 == bytes_to_copy) &&
874  {
876  "Pausing MHD download %s%s, no data available\n",
877  s5r->domain,
878  s5r->url);
879  if (NULL != s5r->curl)
880  {
882  "Continuing CURL interaction for %s%s\n",
883  s5r->domain,
884  s5r->url);
885  if (GNUNET_YES == s5r->curl_paused)
886  {
887  s5r->curl_paused = GNUNET_NO;
888  curl_easy_pause(s5r->curl,
889  CURLPAUSE_CONT);
890  }
892  }
893  if (GNUNET_NO == s5r->suspended)
894  {
895  MHD_suspend_connection(s5r->con);
896  s5r->suspended = GNUNET_YES;
897  }
898  return 0; /* more data later */
899  }
900  if ((0 == bytes_to_copy) &&
902  {
904  "Completed MHD download %s%s\n",
905  s5r->domain,
906  s5r->url);
907  return MHD_CONTENT_READER_END_OF_STREAM;
908  }
910  "Writing %llu/%llu bytes to %s%s\n",
911  (unsigned long long)bytes_to_copy,
912  (unsigned long long)s5r->io_len,
913  s5r->domain,
914  s5r->url);
916  s5r->io_buf,
917  bytes_to_copy);
918  memmove(s5r->io_buf,
919  &s5r->io_buf[bytes_to_copy],
920  s5r->io_len - bytes_to_copy);
921  s5r->io_len -= bytes_to_copy;
922  if ((NULL != s5r->curl) &&
923  (GNUNET_YES == s5r->curl_paused))
924  {
926  "Continuing CURL interaction for %s%s\n",
927  s5r->domain,
928  s5r->url);
929  s5r->curl_paused = GNUNET_NO;
930  curl_easy_pause(s5r->curl,
931  CURLPAUSE_CONT);
932  }
933  return bytes_to_copy;
934 }
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 946 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().

947 {
948  unsigned int cert_list_size;
949  const gnutls_datum_t *chainp;
950  const struct curl_tlssessioninfo *tlsinfo;
951  char certdn[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 3];
952  size_t size;
953  gnutls_x509_crt_t x509_cert;
954  int rc;
955  const char *name;
956 
957  s5r->ssl_checked = GNUNET_YES;
959  "Checking X.509 certificate\n");
960  if (CURLE_OK !=
961  curl_easy_getinfo(s5r->curl,
962  CURLINFO_TLS_SESSION,
963  &tlsinfo))
964  return GNUNET_SYSERR;
965  if (CURLSSLBACKEND_GNUTLS != tlsinfo->backend)
966  {
968  _("Unsupported CURL TLS backend %d\n"),
969  tlsinfo->backend);
970  return GNUNET_SYSERR;
971  }
972  chainp = gnutls_certificate_get_peers(tlsinfo->internals,
973  &cert_list_size);
974  if ((!chainp) ||
975  (0 == cert_list_size))
976  return GNUNET_SYSERR;
977 
978  size = sizeof(certdn);
979  /* initialize an X.509 certificate structure. */
980  gnutls_x509_crt_init(&x509_cert);
981  gnutls_x509_crt_import(x509_cert,
982  chainp,
983  GNUTLS_X509_FMT_DER);
984 
985  if (0 != (rc = gnutls_x509_crt_get_dn_by_oid(x509_cert,
986  GNUTLS_OID_X520_COMMON_NAME,
987  0, /* the first and only one */
988  0 /* no DER encoding */,
989  certdn,
990  &size)))
991  {
993  _("Failed to fetch CN from cert: %s\n"),
994  gnutls_strerror(rc));
995  gnutls_x509_crt_deinit(x509_cert);
996  return GNUNET_SYSERR;
997  }
998  /* check for TLSA/DANE records */
999 #if HAVE_GNUTLS_DANE
1000  if (0 != s5r->num_danes)
1001  {
1002  dane_state_t dane_state;
1003  dane_query_t dane_query;
1004  unsigned int verify;
1005 
1006  /* FIXME: add flags to gnutls to NOT read UNBOUND_ROOT_KEY_FILE here! */
1007  if (0 != (rc = dane_state_init(&dane_state,
1008 #ifdef DANE_F_IGNORE_DNSSEC
1009  DANE_F_IGNORE_DNSSEC |
1010 #endif
1011  DANE_F_IGNORE_LOCAL_RESOLVER)))
1012  {
1014  _("Failed to initialize DANE: %s\n"),
1015  dane_strerror(rc));
1016  gnutls_x509_crt_deinit(x509_cert);
1017  return GNUNET_SYSERR;
1018  }
1019  s5r->dane_data[s5r->num_danes] = NULL;
1020  s5r->dane_data_len[s5r->num_danes] = 0;
1021  if (0 != (rc = dane_raw_tlsa(dane_state,
1022  &dane_query,
1023  s5r->dane_data,
1024  s5r->dane_data_len,
1025  GNUNET_YES,
1026  GNUNET_NO)))
1027  {
1029  _("Failed to parse DANE record: %s\n"),
1030  dane_strerror(rc));
1031  dane_state_deinit(dane_state);
1032  gnutls_x509_crt_deinit(x509_cert);
1033  return GNUNET_SYSERR;
1034  }
1035  if (0 != (rc = dane_verify_crt_raw(dane_state,
1036  chainp,
1037  cert_list_size,
1038  gnutls_certificate_type_get(tlsinfo->internals),
1039  dane_query,
1040  0, 0,
1041  &verify)))
1042  {
1044  _("Failed to verify TLS connection using DANE: %s\n"),
1045  dane_strerror(rc));
1046  dane_query_deinit(dane_query);
1047  dane_state_deinit(dane_state);
1048  gnutls_x509_crt_deinit(x509_cert);
1049  return GNUNET_SYSERR;
1050  }
1051  if (0 != verify)
1052  {
1054  _("Failed DANE verification failed with GnuTLS verify status code: %u\n"),
1055  verify);
1056  dane_query_deinit(dane_query);
1057  dane_state_deinit(dane_state);
1058  gnutls_x509_crt_deinit(x509_cert);
1059  return GNUNET_SYSERR;
1060  }
1061  dane_query_deinit(dane_query);
1062  dane_state_deinit(dane_state);
1063  /* success! */
1064  }
1065  else
1066 #endif
1067  {
1068  /* try LEHO or ordinary domain name X509 verification */
1069  name = s5r->domain;
1070  if (NULL != s5r->leho)
1071  name = s5r->leho;
1072  if (NULL != name)
1073  {
1074  if (0 == (rc = gnutls_x509_crt_check_hostname(x509_cert,
1075  name)))
1076  {
1078  _("TLS certificate subject name (%s) does not match `%s': %d\n"),
1079  certdn,
1080  name,
1081  rc);
1082  gnutls_x509_crt_deinit(x509_cert);
1083  return GNUNET_SYSERR;
1084  }
1085  }
1086  else
1087  {
1088  /* we did not even have the domain name!? */
1089  GNUNET_break(0);
1090  return GNUNET_SYSERR;
1091  }
1092  }
1093  gnutls_x509_crt_deinit(x509_cert);
1094  return GNUNET_OK;
1095 }
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.
static int verify
Verify mode.
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:66
const char * name
char * leho
DNS Legacy Host Name as given by GNS, NULL if not given.
#define GNUNET_log(kind,...)
#define GNUNET_YES
Definition: gnunet_common.h:77
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 1111 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().

1115 {
1116  struct Socks5Request *s5r = cls;
1117  struct HttpResponseHeader *header;
1118  size_t bytes = size * nmemb;
1119  char *ndup;
1120  const char *hdr_type;
1121  const char *cookie_domain;
1122  char *hdr_val;
1123  char *new_cookie_hdr;
1124  char *new_location;
1125  size_t offset;
1126  size_t delta_cdomain;
1127  int domain_matched;
1128  char *tok;
1129 
1131  "Receiving HTTP response header from CURL\n");
1132  /* first, check TLS certificate */
1133  if ((GNUNET_YES != s5r->ssl_checked) &&
1134  (GNUNET_YES == s5r->is_tls))
1135  //(HTTPS_PORT == s5r->port))
1136  {
1137  if (GNUNET_OK != check_ssl_certificate(s5r))
1138  return 0;
1139  }
1140  ndup = GNUNET_strndup(buffer,
1141  bytes);
1142  hdr_type = strtok(ndup,
1143  ":");
1144  if (NULL == hdr_type)
1145  {
1146  GNUNET_free(ndup);
1147  return bytes;
1148  }
1149  hdr_val = strtok(NULL,
1150  "");
1151  if (NULL == hdr_val)
1152  {
1153  GNUNET_free(ndup);
1154  return bytes;
1155  }
1156  if (' ' == *hdr_val)
1157  hdr_val++;
1158 
1159  /* custom logic for certain header types */
1160  new_cookie_hdr = NULL;
1161  if ((NULL != s5r->leho) &&
1162  (0 == strcasecmp(hdr_type,
1163  MHD_HTTP_HEADER_SET_COOKIE)))
1164 
1165  {
1166  new_cookie_hdr = GNUNET_malloc(strlen(hdr_val) +
1167  strlen(s5r->domain) + 1);
1168  offset = 0;
1169  domain_matched = GNUNET_NO; /* make sure we match domain at most once */
1170  for (tok = strtok(hdr_val, ";"); NULL != tok; tok = strtok(NULL, ";"))
1171  {
1172  if ((0 == strncasecmp(tok,
1173  " domain",
1174  strlen(" domain"))) &&
1175  (GNUNET_NO == domain_matched))
1176  {
1177  domain_matched = GNUNET_YES;
1178  cookie_domain = tok + strlen(" domain") + 1;
1179  if (strlen(cookie_domain) < strlen(s5r->leho))
1180  {
1181  delta_cdomain = strlen(s5r->leho) - strlen(cookie_domain);
1182  if (0 == strcasecmp(cookie_domain,
1183  s5r->leho + delta_cdomain))
1184  {
1185  offset += sprintf(new_cookie_hdr + offset,
1186  " domain=%s;",
1187  s5r->domain);
1188  continue;
1189  }
1190  }
1191  else if (0 == strcmp(cookie_domain,
1192  s5r->leho))
1193  {
1194  offset += sprintf(new_cookie_hdr + offset,
1195  " domain=%s;",
1196  s5r->domain);
1197  continue;
1198  }
1199  else if (('.' == cookie_domain[0]) &&
1200  (0 == strcmp(&cookie_domain[1],
1201  s5r->leho)))
1202  {
1203  offset += sprintf(new_cookie_hdr + offset,
1204  " domain=.%s;",
1205  s5r->domain);
1206  continue;
1207  }
1209  _("Cookie domain `%s' supplied by server is invalid\n"),
1210  tok);
1211  }
1212  GNUNET_memcpy(new_cookie_hdr + offset,
1213  tok,
1214  strlen(tok));
1215  offset += strlen(tok);
1216  new_cookie_hdr[offset++] = ';';
1217  }
1218  hdr_val = new_cookie_hdr;
1219  }
1220 
1221  new_location = NULL;
1222  if (0 == strcasecmp(MHD_HTTP_HEADER_TRANSFER_ENCODING,
1223  hdr_type))
1224  {
1225  /* Ignore transfer encoding, set automatically by MHD if required */
1226  goto cleanup;
1227  }
1228  if ((0 == strcasecmp(MHD_HTTP_HEADER_LOCATION,
1229  hdr_type)))
1230  {
1231  char *leho_host;
1232 
1233  GNUNET_asprintf(&leho_host,
1234  (GNUNET_YES != s5r->is_tls) //(HTTPS_PORT != s5r->port)
1235  ? "http://%s"
1236  : "https://%s",
1237  s5r->leho);
1238  if (0 == strncmp(leho_host,
1239  hdr_val,
1240  strlen(leho_host)))
1241  {
1242  GNUNET_asprintf(&new_location,
1243  "%s%s%s",
1244  (GNUNET_YES != s5r->is_tls) //(HTTPS_PORT != s5r->port)
1245  ? "http://"
1246  : "https://",
1247  s5r->domain,
1248  hdr_val + strlen(leho_host));
1249  hdr_val = new_location;
1250  }
1251  GNUNET_free(leho_host);
1252  }
1253  if (0 == strcasecmp(MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
1254  hdr_type))
1255  {
1256  char *leho_host;
1257 
1258  GNUNET_asprintf(&leho_host,
1259  (GNUNET_YES != s5r->is_tls) //(HTTPS_PORT != s5r->port)
1260  ? "http://%s"
1261  : "https://%s",
1262  s5r->leho);
1263  if (0 == strncmp(leho_host,
1264  hdr_val,
1265  strlen(leho_host)))
1266  {
1267  GNUNET_asprintf(&new_location,
1268  "%s%s",
1269  (GNUNET_YES != s5r->is_tls) //(HTTPS_PORT != s5r->port)
1270  ? "http://"
1271  : "https://",
1272  s5r->domain);
1273  hdr_val = new_location;
1274  }
1275  GNUNET_free(leho_host);
1276  }
1277 
1278  /* MHD does not allow certain characters in values, remove those */
1279  if (NULL != (tok = strchr(hdr_val, '\n')))
1280  *tok = '\0';
1281  if (NULL != (tok = strchr(hdr_val, '\r')))
1282  *tok = '\0';
1283  if (NULL != (tok = strchr(hdr_val, '\t')))
1284  *tok = '\0';
1285  if (0 != strlen(hdr_val)) /* Rely in MHD to set those */
1286  {
1288  "Adding header %s: %s to MHD response\n",
1289  hdr_type,
1290  hdr_val);
1291  header = GNUNET_new(struct HttpResponseHeader);
1292  header->type = GNUNET_strdup(hdr_type);
1293  header->value = GNUNET_strdup(hdr_val);
1295  s5r->header_tail,
1296  header);
1297  }
1298 cleanup:
1299  GNUNET_free(ndup);
1300  GNUNET_free_non_null(new_cookie_hdr);
1301  GNUNET_free_non_null(new_location);
1302  return bytes;
1303 }
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:66
#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 1315 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().

1316 {
1317  long resp_code;
1318  double content_length;
1319 
1320  if (NULL != s5r->response)
1321  {
1323  "Response already set!\n");
1324  return GNUNET_SYSERR;
1325  }
1326 
1327  GNUNET_break(CURLE_OK ==
1328  curl_easy_getinfo(s5r->curl,
1329  CURLINFO_RESPONSE_CODE,
1330  &resp_code));
1331  GNUNET_break(CURLE_OK ==
1332  curl_easy_getinfo(s5r->curl,
1333  CURLINFO_CONTENT_LENGTH_DOWNLOAD,
1334  &content_length));
1336  "Creating MHD response with code %d and size %d for %s%s\n",
1337  (int)resp_code,
1338  (int)content_length,
1339  s5r->domain,
1340  s5r->url);
1341  s5r->response_code = resp_code;
1342  s5r->response = MHD_create_response_from_callback((-1 == content_length)
1343  ? MHD_SIZE_UNKNOWN
1344  : content_length,
1345  IO_BUFFERSIZE,
1346  &mhd_content_cb,
1347  s5r,
1348  NULL);
1349  for (struct HttpResponseHeader *header = s5r->header_head;
1350  NULL != header;
1351  header = header->next)
1352  {
1353  if (0 == strcasecmp(header->type,
1354  MHD_HTTP_HEADER_CONTENT_LENGTH))
1355  continue; /* MHD won't let us mess with those, for good reason */
1356  if ((0 == strcasecmp(header->type,
1357  MHD_HTTP_HEADER_TRANSFER_ENCODING)) &&
1358  ((0 == strcasecmp(header->value,
1359  "identity")) ||
1360  (0 == strcasecmp(header->value,
1361  "chunked"))))
1362  continue; /* MHD won't let us mess with those, for good reason */
1363  if (MHD_YES !=
1364  MHD_add_response_header(s5r->response,
1365  header->type,
1366  header->value))
1367  {
1368  GNUNET_break(0);
1370  "Failed to add header `%s:%s'\n",
1371  header->type,
1372  header->value);
1373  }
1374  }
1375  /* force connection to be closed after each request, as we
1376  do not support HTTP pipelining (yet, FIXME!) */
1377  /*GNUNET_break (MHD_YES ==
1378  MHD_add_response_header (s5r->response,
1379  MHD_HTTP_HEADER_CONNECTION,
1380  "close"));*/
1381  MHD_resume_connection(s5r->con);
1382  s5r->suspended = GNUNET_NO;
1383  return GNUNET_OK;
1384 }
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 1398 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().

1402 {
1403  struct Socks5Request *s5r = ctx;
1404  size_t total = size * nmemb;
1405 
1407  "Receiving %ux%u bytes for `%s%s' from cURL to download\n",
1408  (unsigned int)size,
1409  (unsigned int)nmemb,
1410  s5r->domain,
1411  s5r->url);
1412  if (NULL == s5r->response)
1415  if ((SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) &&
1416  (0 == s5r->io_len))
1417  {
1419  "Previous upload finished... starting DOWNLOAD.\n");
1421  }
1422  if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
1423  (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1424  {
1425  /* we're still not done with the upload, do not yet
1426  start the download, the IO buffer is still full
1427  with upload data. */
1429  "Pausing CURL download `%s%s', waiting for UPLOAD to finish\n",
1430  s5r->domain,
1431  s5r->url);
1432  s5r->curl_paused = GNUNET_YES;
1433  return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */
1434  }
1435  if (sizeof(s5r->io_buf) - s5r->io_len < total)
1436  {
1438  "Pausing CURL `%s%s' download, not enough space %llu %llu %llu\n",
1439  s5r->domain,
1440  s5r->url,
1441  (unsigned long long)sizeof(s5r->io_buf),
1442  (unsigned long long)s5r->io_len,
1443  (unsigned long long)total);
1444  s5r->curl_paused = GNUNET_YES;
1445  return CURL_WRITEFUNC_PAUSE; /* not enough space */
1446  }
1447  GNUNET_memcpy(&s5r->io_buf[s5r->io_len],
1448  ptr,
1449  total);
1450  s5r->io_len += total;
1451  if (GNUNET_YES == s5r->suspended)
1452  {
1453  MHD_resume_connection(s5r->con);
1454  s5r->suspended = GNUNET_NO;
1455  }
1457  "Received %llu bytes of payload via cURL from %s\n",
1458  (unsigned long long)total,
1459  s5r->domain);
1460  if (s5r->io_len == total)
1461  run_mhd_now(s5r->hd);
1462  return total;
1463 }
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:66
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 1477 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().

1481 {
1482  struct Socks5Request *s5r = cls;
1483  size_t len = size * nmemb;
1484  size_t to_copy;
1485 
1487  "Receiving %ux%u bytes for `%s%s' from cURL to upload\n",
1488  (unsigned int)size,
1489  (unsigned int)nmemb,
1490  s5r->domain,
1491  s5r->url);
1492 
1493  if ((0 == s5r->io_len) &&
1494  (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1495  {
1497  "Pausing CURL UPLOAD %s%s, need more data\n",
1498  s5r->domain,
1499  s5r->url);
1500  return CURL_READFUNC_PAUSE;
1501  }
1502  if ((0 == s5r->io_len) &&
1503  (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1504  {
1506  if (GNUNET_YES == s5r->curl_paused)
1507  {
1508  s5r->curl_paused = GNUNET_NO;
1509  curl_easy_pause(s5r->curl,
1510  CURLPAUSE_CONT);
1511  }
1513  "Completed CURL UPLOAD %s%s\n",
1514  s5r->domain,
1515  s5r->url);
1516  return 0; /* upload finished, can now download */
1517  }
1518  if ((SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) &&
1519  (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1520  {
1521  GNUNET_break(0);
1522  return CURL_READFUNC_ABORT;
1523  }
1524  to_copy = GNUNET_MIN(s5r->io_len,
1525  len);
1527  s5r->io_buf,
1528  to_copy);
1529  memmove(s5r->io_buf,
1530  &s5r->io_buf[to_copy],
1531  s5r->io_len - to_copy);
1532  s5r->io_len -= to_copy;
1533  if (s5r->io_len + to_copy == sizeof(s5r->io_buf))
1534  run_mhd_now(s5r->hd); /* got more space for upload now */
1535  return to_copy;
1536 }
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:66
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 1634 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().

1635 {
1636  int running;
1637  int msgnum;
1638  struct CURLMsg *msg;
1639  CURLMcode mret;
1640  struct Socks5Request *s5r;
1641 
1642  curl_download_task = NULL;
1644  "Running CURL interaction\n");
1645  do
1646  {
1647  running = 0;
1648  mret = curl_multi_perform(curl_multi,
1649  &running);
1651  "Checking CURL multi status: %d\n",
1652  mret);
1653  while (NULL != (msg = curl_multi_info_read(curl_multi,
1654  &msgnum)))
1655  {
1656  GNUNET_break(CURLE_OK ==
1657  curl_easy_getinfo(msg->easy_handle,
1658  CURLINFO_PRIVATE,
1659  (char **)&s5r));
1660  if (NULL == s5r)
1661  {
1662  GNUNET_break(0);
1663  continue;
1664  }
1665  switch (msg->msg)
1666  {
1667  case CURLMSG_NONE:
1668  /* documentation says this is not used */
1669  GNUNET_break(0);
1670  break;
1671 
1672  case CURLMSG_DONE:
1673  switch (msg->data.result)
1674  {
1675  case CURLE_OK:
1676  case CURLE_GOT_NOTHING:
1678  "CURL download %s%s completed.\n",
1679  s5r->domain,
1680  s5r->url);
1681  if (NULL == s5r->response)
1682  {
1685  }
1687  if (GNUNET_YES == s5r->suspended)
1688  {
1689  MHD_resume_connection(s5r->con);
1690  s5r->suspended = GNUNET_NO;
1691  }
1692  run_mhd_now(s5r->hd);
1693  break;
1694 
1695  default:
1697  "Download curl %s%s failed: %s\n",
1698  s5r->domain,
1699  s5r->url,
1700  curl_easy_strerror(msg->data.result));
1701  /* FIXME: indicate error somehow? close MHD connection badly as well? */
1703  if (GNUNET_YES == s5r->suspended)
1704  {
1705  MHD_resume_connection(s5r->con);
1706  s5r->suspended = GNUNET_NO;
1707  }
1708  run_mhd_now(s5r->hd);
1709  break;
1710  }
1711  if (NULL == s5r->response)
1713  break;
1714 
1715  case CURLMSG_LAST:
1716  /* documentation says this is not used */
1717  GNUNET_break(0);
1718  break;
1719 
1720  default:
1721  /* unexpected status code */
1722  GNUNET_break(0);
1723  break;
1724  }
1725  }
1726  ;
1727  }
1728  while (mret == CURLM_CALL_MULTI_PERFORM);
1729  if (CURLM_OK != mret)
1731  "%s failed at %s:%d: `%s'\n",
1732  "curl_multi_perform", __FILE__, __LINE__,
1733  curl_multi_strerror(mret));
1734  if (0 == running)
1735  {
1737  "Suspending cURL multi loop, no more events pending\n");
1738  if (NULL != curl_download_task)
1739  {
1741  curl_download_task = NULL;
1742  }
1743  return; /* nothing more in progress */
1744  }
1746 }
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:956
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 1766 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().

1770 {
1771  struct Socks5Request *s5r = cls;
1772  char *hdr;
1773 
1774  if ((0 == strcasecmp(MHD_HTTP_HEADER_HOST,
1775  key)) &&
1776  (NULL != s5r->leho))
1777  value = s5r->leho;
1778  GNUNET_asprintf(&hdr,
1779  "%s: %s",
1780  key,
1781  value);
1783  "Adding HEADER `%s' to HTTP request\n",
1784  hdr);
1785  s5r->headers = curl_slist_append(s5r->headers,
1786  hdr);
1787  GNUNET_free(hdr);
1788  return MHD_YES;
1789 }
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 1816 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().

1824 {
1825  struct Socks5Request *s5r = *con_cls;
1826  char *curlurl;
1827  char ipstring[INET6_ADDRSTRLEN];
1828  char ipaddr[INET6_ADDRSTRLEN + 2];
1829  const struct sockaddr *sa;
1830  const struct sockaddr_in *s4;
1831  const struct sockaddr_in6 *s6;
1832  uint16_t port;
1833  size_t left;
1834 
1835  if (NULL == s5r)
1836  {
1837  GNUNET_break(0);
1838  return MHD_NO;
1839  }
1840  s5r->con = con;
1841  /* Fresh connection. */
1842  if (SOCKS5_SOCKET_WITH_MHD == s5r->state)
1843  {
1844  /* first time here, initialize curl handle */
1845  if (s5r->is_gns)
1846  {
1847  sa = (const struct sockaddr *)&s5r->destination_address;
1848  switch (sa->sa_family)
1849  {
1850  case AF_INET:
1851  s4 = (const struct sockaddr_in *)&s5r->destination_address;
1852  if (NULL == inet_ntop(AF_INET,
1853  &s4->sin_addr,
1854  ipstring,
1855  sizeof(ipstring)))
1856  {
1857  GNUNET_break(0);
1858  return MHD_NO;
1859  }
1860  GNUNET_snprintf(ipaddr,
1861  sizeof(ipaddr),
1862  "%s",
1863  ipstring);
1864  port = ntohs(s4->sin_port);
1865  break;
1866 
1867  case AF_INET6:
1868  s6 = (const struct sockaddr_in6 *)&s5r->destination_address;
1869  if (NULL == inet_ntop(AF_INET6,
1870  &s6->sin6_addr,
1871  ipstring,
1872  sizeof(ipstring)))
1873  {
1874  GNUNET_break(0);
1875  return MHD_NO;
1876  }
1877  GNUNET_snprintf(ipaddr,
1878  sizeof(ipaddr),
1879  "%s",
1880  ipstring);
1881  port = ntohs(s6->sin6_port);
1882  break;
1883 
1884  default:
1885  GNUNET_break(0);
1886  return MHD_NO;
1887  }
1888  }
1889  else
1890  {
1891  port = s5r->port;
1892  }
1893  if (NULL == s5r->curl)
1894  s5r->curl = curl_easy_init();
1895  if (NULL == s5r->curl)
1896  return MHD_queue_response(con,
1897  MHD_HTTP_INTERNAL_SERVER_ERROR,
1899  curl_easy_setopt(s5r->curl,
1900  CURLOPT_HEADERFUNCTION,
1901  &curl_check_hdr);
1902  curl_easy_setopt(s5r->curl,
1903  CURLOPT_HEADERDATA,
1904  s5r);
1905  curl_easy_setopt(s5r->curl,
1906  CURLOPT_FOLLOWLOCATION,
1907  0);
1908  if (s5r->is_gns)
1909  curl_easy_setopt(s5r->curl,
1910  CURLOPT_IPRESOLVE,
1911  CURL_IPRESOLVE_V4);
1912  curl_easy_setopt(s5r->curl,
1913  CURLOPT_CONNECTTIMEOUT,
1914  600L);
1915  curl_easy_setopt(s5r->curl,
1916  CURLOPT_TIMEOUT,
1917  600L);
1918  curl_easy_setopt(s5r->curl,
1919  CURLOPT_NOSIGNAL,
1920  1L);
1921  curl_easy_setopt(s5r->curl,
1922  CURLOPT_HTTP_CONTENT_DECODING,
1923  0);
1924  curl_easy_setopt(s5r->curl,
1925  CURLOPT_NOSIGNAL,
1926  1L);
1927  curl_easy_setopt(s5r->curl,
1928  CURLOPT_PRIVATE,
1929  s5r);
1930  curl_easy_setopt(s5r->curl,
1931  CURLOPT_VERBOSE,
1932  0L);
1938  if (NULL != s5r->leho)
1939  {
1940  char *curl_hosts;
1941 
1942  GNUNET_asprintf(&curl_hosts,
1943  "%s:%d:%s",
1944  s5r->leho,
1945  port,
1946  ipaddr);
1947  s5r->hosts = curl_slist_append(NULL,
1948  curl_hosts);
1949  curl_easy_setopt(s5r->curl,
1950  CURLOPT_RESOLVE,
1951  s5r->hosts);
1952  GNUNET_free(curl_hosts);
1953  }
1954  if (s5r->is_gns)
1955  {
1956  GNUNET_asprintf(&curlurl,
1957  (GNUNET_YES != s5r->is_tls) //(HTTPS_PORT != s5r->port)
1958  ? "http://%s:%d%s"
1959  : "https://%s:%d%s",
1960  (NULL != s5r->leho)
1961  ? s5r->leho
1962  : ipaddr,
1963  port,
1964  s5r->url);
1965  }
1966  else
1967  {
1968  GNUNET_asprintf(&curlurl,
1969  (GNUNET_YES != s5r->is_tls) //(HTTPS_PORT != s5r->port)
1970  ? "http://%s:%d%s"
1971  : "https://%s:%d%s",
1972  s5r->domain,
1973  port,
1974  s5r->url);
1975  }
1976  curl_easy_setopt(s5r->curl,
1977  CURLOPT_URL,
1978  curlurl);
1980  "Launching %s CURL interaction, fetching `%s'\n",
1981  (s5r->is_gns) ? "GNS" : "DNS",
1982  curlurl);
1983  GNUNET_free(curlurl);
1984  if (0 == strcasecmp(meth,
1985  MHD_HTTP_METHOD_PUT))
1986  {
1988  curl_easy_setopt(s5r->curl,
1989  CURLOPT_UPLOAD,
1990  1L);
1991  curl_easy_setopt(s5r->curl,
1992  CURLOPT_WRITEFUNCTION,
1993  &curl_download_cb);
1994  curl_easy_setopt(s5r->curl,
1995  CURLOPT_WRITEDATA,
1996  s5r);
1997  GNUNET_assert(CURLE_OK ==
1998  curl_easy_setopt(s5r->curl,
1999  CURLOPT_READFUNCTION,
2000  &curl_upload_cb));
2001  curl_easy_setopt(s5r->curl,
2002  CURLOPT_READDATA,
2003  s5r);
2004  {
2005  const char *us;
2006  long upload_size = 0;
2007 
2008  us = MHD_lookup_connection_value(con,
2009  MHD_HEADER_KIND,
2010  MHD_HTTP_HEADER_CONTENT_LENGTH);
2011  if ((1 == sscanf(us,
2012  "%ld",
2013  &upload_size)) &&
2014  (upload_size >= 0))
2015  {
2016  curl_easy_setopt(s5r->curl,
2017  CURLOPT_INFILESIZE,
2018  upload_size);
2019  }
2020  }
2021  }
2022  else if (0 == strcasecmp(meth, MHD_HTTP_METHOD_POST))
2023  {
2025  curl_easy_setopt(s5r->curl,
2026  CURLOPT_POST,
2027  1L);
2028  curl_easy_setopt(s5r->curl,
2029  CURLOPT_WRITEFUNCTION,
2030  &curl_download_cb);
2031  curl_easy_setopt(s5r->curl,
2032  CURLOPT_WRITEDATA,
2033  s5r);
2034  curl_easy_setopt(s5r->curl,
2035  CURLOPT_READFUNCTION,
2036  &curl_upload_cb);
2037  curl_easy_setopt(s5r->curl,
2038  CURLOPT_READDATA,
2039  s5r);
2040  {
2041  const char *us;
2042  long upload_size;
2043 
2044  upload_size = 0;
2045  us = MHD_lookup_connection_value(con,
2046  MHD_HEADER_KIND,
2047  MHD_HTTP_HEADER_CONTENT_LENGTH);
2048  if ((NULL != us) &&
2049  (1 == sscanf(us,
2050  "%ld",
2051  &upload_size)) &&
2052  (upload_size >= 0))
2053  {
2054  curl_easy_setopt(s5r->curl,
2055  CURLOPT_INFILESIZE,
2056  upload_size);
2057  }
2058  else
2059  {
2060  curl_easy_setopt(s5r->curl,
2061  CURLOPT_INFILESIZE,
2062  upload_size);
2063  }
2064  }
2065  }
2066  else if (0 == strcasecmp(meth,
2067  MHD_HTTP_METHOD_HEAD))
2068  {
2070  curl_easy_setopt(s5r->curl,
2071  CURLOPT_NOBODY,
2072  1L);
2073  }
2074  else if (0 == strcasecmp(meth,
2075  MHD_HTTP_METHOD_OPTIONS))
2076  {
2078  curl_easy_setopt(s5r->curl,
2079  CURLOPT_CUSTOMREQUEST,
2080  "OPTIONS");
2081  curl_easy_setopt(s5r->curl,
2082  CURLOPT_WRITEFUNCTION,
2083  &curl_download_cb);
2084  curl_easy_setopt(s5r->curl,
2085  CURLOPT_WRITEDATA,
2086  s5r);
2087  }
2088  else if (0 == strcasecmp(meth,
2089  MHD_HTTP_METHOD_GET))
2090  {
2092  curl_easy_setopt(s5r->curl,
2093  CURLOPT_HTTPGET,
2094  1L);
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_DELETE))
2104  {
2106  curl_easy_setopt(s5r->curl,
2107  CURLOPT_CUSTOMREQUEST,
2108  "DELETE");
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
2117  {
2119  _("Unsupported HTTP method `%s'\n"),
2120  meth);
2121  curl_easy_cleanup(s5r->curl);
2122  s5r->curl = NULL;
2123  return MHD_NO;
2124  }
2125 
2126  if (0 == strcasecmp(ver, MHD_HTTP_VERSION_1_0))
2127  {
2128  curl_easy_setopt(s5r->curl,
2129  CURLOPT_HTTP_VERSION,
2130  CURL_HTTP_VERSION_1_0);
2131  }
2132  else if (0 == strcasecmp(ver, MHD_HTTP_VERSION_1_1))
2133  {
2134  curl_easy_setopt(s5r->curl,
2135  CURLOPT_HTTP_VERSION,
2136  CURL_HTTP_VERSION_1_1);
2137  }
2138  else
2139  {
2140  curl_easy_setopt(s5r->curl,
2141  CURLOPT_HTTP_VERSION,
2142  CURL_HTTP_VERSION_NONE);
2143  }
2144 
2145  if (GNUNET_YES == s5r->is_tls) //(HTTPS_PORT == s5r->port)
2146  {
2147  curl_easy_setopt(s5r->curl,
2148  CURLOPT_USE_SSL,
2149  CURLUSESSL_ALL);
2150  if (0 < s5r->num_danes)
2151  curl_easy_setopt(s5r->curl,
2152  CURLOPT_SSL_VERIFYPEER,
2153  0L);
2154  else
2155  curl_easy_setopt(s5r->curl,
2156  CURLOPT_SSL_VERIFYPEER,
2157  1L);
2158  /* Disable cURL checking the hostname, as we will check ourselves
2159  as only we have the domain name or the LEHO or the DANE record */
2160  curl_easy_setopt(s5r->curl,
2161  CURLOPT_SSL_VERIFYHOST,
2162  0L);
2163  }
2164  else
2165  {
2166  curl_easy_setopt(s5r->curl,
2167  CURLOPT_USE_SSL,
2168  CURLUSESSL_NONE);
2169  }
2170 
2171  if (CURLM_OK !=
2172  curl_multi_add_handle(curl_multi,
2173  s5r->curl))
2174  {
2175  GNUNET_break(0);
2176  curl_easy_cleanup(s5r->curl);
2177  s5r->curl = NULL;
2178  return MHD_NO;
2179  }
2180  MHD_get_connection_values(con,
2181  MHD_HEADER_KIND,
2182  (MHD_KeyValueIterator) & con_val_iter,
2183  s5r);
2184  curl_easy_setopt(s5r->curl,
2185  CURLOPT_HTTPHEADER,
2186  s5r->headers);
2188  return MHD_YES;
2189  }
2190 
2191  /* continuing to process request */
2192  if (0 != *upload_data_size)
2193  {
2195  "Processing %u bytes UPLOAD\n",
2196  (unsigned int)*upload_data_size);
2197 
2198  /* FIXME: This must be set or a header with Transfer-Encoding: chunked. Else
2199  * upload callback is not called!
2200  */
2201  curl_easy_setopt(s5r->curl,
2202  CURLOPT_POSTFIELDSIZE,
2203  *upload_data_size);
2204 
2205  left = GNUNET_MIN(*upload_data_size,
2206  sizeof(s5r->io_buf) - s5r->io_len);
2207  GNUNET_memcpy(&s5r->io_buf[s5r->io_len],
2208  upload_data,
2209  left);
2210  s5r->io_len += left;
2211  *upload_data_size -= left;
2212  GNUNET_assert(NULL != s5r->curl);
2213  if (GNUNET_YES == s5r->curl_paused)
2214  {
2215  s5r->curl_paused = GNUNET_NO;
2216  curl_easy_pause(s5r->curl,
2217  CURLPAUSE_CONT);
2218  }
2219  return MHD_YES;
2220  }
2221  if (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state)
2222  {
2224  "Finished processing UPLOAD\n");
2226  }
2227  if (NULL == s5r->response)
2228  {
2230  "Waiting for HTTP response for %s%s...\n",
2231  s5r->domain,
2232  s5r->url);
2233  MHD_suspend_connection(con);
2234  s5r->suspended = GNUNET_YES;
2235  return MHD_YES;
2236  }
2238  "Queueing response for %s%s with MHD\n",
2239  s5r->domain,
2240  s5r->url);
2241  run_mhd_now(s5r->hd);
2242  return MHD_queue_response(con,
2243  s5r->response_code,
2244  s5r->response);
2245 }
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 2261 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().

2265 {
2266  struct Socks5Request *s5r = *con_cls;
2267 
2268  if (NULL == s5r)
2269  return;
2270  if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
2272  "MHD encountered error handling request: %d\n",
2273  toe);
2274  if (NULL != s5r->curl)
2275  {
2277  "Removing cURL handle (MHD interaction complete)\n");
2278  curl_multi_remove_handle(curl_multi,
2279  s5r->curl);
2280  curl_slist_free_all(s5r->headers);
2281  s5r->headers = NULL;
2282  curl_easy_reset(s5r->curl);
2283  s5r->rbuf_len = 0;
2284  s5r->wbuf_len = 0;
2285  s5r->io_len = 0;
2287  }
2288  if ((NULL != s5r->response) &&
2289  (curl_failure_response != s5r->response))
2290  MHD_destroy_response(s5r->response);
2291  for (struct HttpResponseHeader *header = s5r->header_head;
2292  NULL != header;
2293  header = s5r->header_head)
2294  {
2296  s5r->header_tail,
2297  header);
2298  GNUNET_free(header->type);
2299  GNUNET_free(header->value);
2300  GNUNET_free(header);
2301  }
2303  "Finished request for %s\n",
2304  s5r->url);
2305  GNUNET_free(s5r->url);
2307  s5r->url = NULL;
2308  s5r->response = NULL;
2309  *con_cls = NULL;
2310 }
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 2323 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().

2327 {
2328  struct Socks5Request *s5r;
2329  const union MHD_ConnectionInfo *ci;
2330  int sock;
2331 
2332  switch (cnc)
2333  {
2334  case MHD_CONNECTION_NOTIFY_STARTED:
2335  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
2336  ci = MHD_get_connection_info(connection,
2337  MHD_CONNECTION_INFO_CONNECTION_FD);
2338  if (NULL == ci)
2339  {
2340  GNUNET_break(0);
2341  return;
2342  }
2343  sock = ci->connect_fd;
2344  for (s5r = s5r_head; NULL != s5r; s5r = s5r->next)
2345  {
2346  if (GNUNET_NETWORK_get_fd(s5r->sock) == sock)
2347  {
2349  "Context set...\n");
2350  s5r->ssl_checked = GNUNET_NO;
2351  *con_cls = s5r;
2352  break;
2353  }
2354  }
2355  break;
2356 
2357  case MHD_CONNECTION_NOTIFY_CLOSED:
2359  "Connection closed... cleaning up\n");
2360  s5r = *con_cls;
2361  if (NULL == s5r)
2362  {
2364  "Connection stale!\n");
2365  return;
2366  }
2367  cleanup_s5r(s5r);
2369  *con_cls = NULL;
2370  break;
2371 
2372  default:
2373  GNUNET_break(0);
2374  }
2375 }
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition: network.c:1068
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 2391 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().

2394 {
2395  struct Socks5Request *s5r;
2396  const union MHD_ConnectionInfo *ci;
2397 
2398  ci = MHD_get_connection_info(connection,
2399  MHD_CONNECTION_INFO_SOCKET_CONTEXT);
2400  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
2401  if (NULL == ci)
2402  {
2403  GNUNET_break(0);
2404  return NULL;
2405  }
2406  s5r = ci->socket_context;
2407  if (NULL != s5r->url)
2408  {
2409  GNUNET_break(0);
2410  return NULL;
2411  }
2412  s5r->url = GNUNET_strdup(url);
2413  if (NULL != s5r->timeout_task)
2414  {
2416  s5r->timeout_task = NULL;
2417  }
2419  return s5r;
2420 }
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:956
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 2429 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().

2430 {
2433  hd);
2435  MHD_stop_daemon(hd->daemon);
2436  if (NULL != hd->httpd_task)
2437  {
2439  hd->httpd_task = NULL;
2440  }
2442  if (hd == httpd)
2443  httpd = NULL;
2444  GNUNET_free(hd);
2445 }
#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:956
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 2454 of file gnunet-gns-proxy.c.

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

Referenced by schedule_httpd().

2455 {
2456  struct MhdHttpList *hd = cls;
2457 
2458  hd->httpd_task = NULL;
2459  kill_httpd(hd);
2460 }
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 2558 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().

2559 {
2560  struct MhdHttpList *hd = cls;
2561 
2562  hd->httpd_task = NULL;
2563  MHD_run(hd->daemon);
2564  schedule_httpd(hd);
2565 }
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 2480 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().

2481 {
2482  fd_set rs;
2483  fd_set ws;
2484  fd_set es;
2485  struct GNUNET_NETWORK_FDSet *wrs;
2486  struct GNUNET_NETWORK_FDSet *wws;
2487  int max;
2488  int haveto;
2489  MHD_UNSIGNED_LONG_LONG timeout;
2490  struct GNUNET_TIME_Relative tv;
2491 
2492  FD_ZERO(&rs);
2493  FD_ZERO(&ws);
2494  FD_ZERO(&es);
2495  max = -1;
2496  if (MHD_YES !=
2497  MHD_get_fdset(hd->daemon,
2498  &rs,
2499  &ws,
2500  &es,
2501  &max))
2502  {
2503  kill_httpd(hd);
2504  return;
2505  }
2506  haveto = MHD_get_timeout(hd->daemon,
2507  &timeout);
2508  if (MHD_YES == haveto)
2509  tv.rel_value_us = (uint64_t)timeout * 1000LL;
2510  else
2512  if (-1 != max)
2513  {
2516  GNUNET_NETWORK_fdset_copy_native(wrs, &rs, max + 1);
2517  GNUNET_NETWORK_fdset_copy_native(wws, &ws, max + 1);
2518  }
2519  else
2520  {
2521  wrs = NULL;
2522  wws = NULL;
2523  }
2524  if (NULL != hd->httpd_task)
2525  {
2527  hd->httpd_task = NULL;
2528  }
2529  if ((MHD_YES != haveto) &&
2530  (-1 == max) &&
2531  (hd != httpd))
2532  {
2533  /* daemon is idle, kill after timeout */
2535  &kill_httpd_task,
2536  hd);
2537  }
2538  else
2539  {
2540  hd->httpd_task =
2542  tv, wrs, wws,
2543  &do_httpd, hd);
2544  }
2545  if (NULL != wrs)
2547  if (NULL != wws)
2549 }
#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:1108
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1254
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:1237
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1238
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition: gnunet-arm.c:114
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:1784
#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:956
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 2591 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().

2593 {
2594  void *buffer;
2595  uint64_t fsize;
2596 
2597  if (GNUNET_OK !=
2599  &fsize,
2600  GNUNET_YES,
2601  GNUNET_YES))
2602  return NULL;
2603  if (fsize > MAX_PEM_SIZE)
2604  return NULL;
2605  *size = (unsigned int)fsize;
2606  buffer = GNUNET_malloc(*size);
2607  if (fsize !=
2609  buffer,
2610  (size_t)fsize))
2611  {
2612  GNUNET_free(buffer);
2613  return NULL;
2614  }
2615  return buffer;
2616 }
#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:66
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:254
#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:791
#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 2627 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().

2629 {
2630  gnutls_datum_t key_data;
2631  int ret;
2632 
2633  key_data.data = load_file(keyfile,
2634  &key_data.size);
2635  if (NULL == key_data.data)
2636  return GNUNET_SYSERR;
2637  ret = gnutls_x509_privkey_import(key, &key_data,
2638  GNUTLS_X509_FMT_PEM);
2639  if (GNUTLS_E_SUCCESS != ret)
2640  {
2642  _("Unable to import private key from file `%s'\n"),
2643  keyfile);
2644  }
2645  GNUNET_free_non_null(key_data.data);
2646  return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2647 }
#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.
static int ret
Final status code.
Definition: gnunet-arm.c:89
#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 2658 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().

2660 {
2661  gnutls_datum_t cert_data;
2662  int ret;
2663 
2664  cert_data.data = load_file(certfile,
2665  &cert_data.size);
2666  if (NULL == cert_data.data)
2667  return GNUNET_SYSERR;
2668  ret = gnutls_x509_crt_import(crt,
2669  &cert_data,
2670  GNUTLS_X509_FMT_PEM);
2671  if (GNUTLS_E_SUCCESS != ret)
2672  {
2674  _("Unable to import certificate from `%s'\n"),
2675  certfile);
2676  }
2677  GNUNET_free_non_null(cert_data.data);
2678  return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2679 }
#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.
static int ret
Final status code.
Definition: gnunet-arm.c:89
#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 2689 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().

2690 {
2691  unsigned int serial;
2692  size_t key_buf_size;
2693  size_t cert_buf_size;
2694  gnutls_x509_crt_t request;
2695  time_t etime;
2696  struct tm *tm_data;
2697  struct ProxyGNSCertificate *pgc;
2698 
2700  "Generating x.509 certificate for `%s'\n",
2701  name);
2702  GNUNET_break(GNUTLS_E_SUCCESS == gnutls_x509_crt_init(&request));
2703  GNUNET_break(GNUTLS_E_SUCCESS == gnutls_x509_crt_set_key(request, proxy_ca.key));
2704  pgc = GNUNET_new(struct ProxyGNSCertificate);
2705  gnutls_x509_crt_set_dn_by_oid(request,
2706  GNUTLS_OID_X520_COUNTRY_NAME,
2707  0,
2708  "ZZ",
2709  strlen("ZZ"));
2710  gnutls_x509_crt_set_dn_by_oid(request,
2711  GNUTLS_OID_X520_ORGANIZATION_NAME,
2712  0,
2713  "GNU Name System",
2714  strlen("GNU Name System"));
2715  gnutls_x509_crt_set_dn_by_oid(request,
2716  GNUTLS_OID_X520_COMMON_NAME,
2717  0,
2718  name,
2719  strlen(name));
2720  gnutls_x509_crt_set_subject_alternative_name(request,
2721  GNUTLS_SAN_DNSNAME,
2722  name);
2723  GNUNET_break(GNUTLS_E_SUCCESS ==
2724  gnutls_x509_crt_set_version(request,
2725  3));
2726  gnutls_rnd(GNUTLS_RND_NONCE,
2727  &serial,
2728  sizeof(serial));
2729  gnutls_x509_crt_set_serial(request,
2730  &serial,
2731  sizeof(serial));
2732  etime = time(NULL);
2733  tm_data = localtime(&etime);
2734  tm_data->tm_hour--;
2735  etime = mktime(tm_data);
2736  gnutls_x509_crt_set_activation_time(request,
2737  etime);
2738  tm_data->tm_year++;
2739  etime = mktime(tm_data);
2740  gnutls_x509_crt_set_expiration_time(request,
2741  etime);
2742  gnutls_x509_crt_sign2(request,
2743  proxy_ca.cert,
2744  proxy_ca.key,
2745  GNUTLS_DIG_SHA512,
2746  0);
2747  key_buf_size = sizeof(pgc->key);
2748  cert_buf_size = sizeof(pgc->cert);
2749  gnutls_x509_crt_export(request,
2750  GNUTLS_X509_FMT_PEM,
2751  pgc->cert,
2752  &cert_buf_size);
2753  gnutls_x509_privkey_export(proxy_ca.key,
2754  GNUTLS_X509_FMT_PEM,
2755  pgc->key,
2756  &key_buf_size);
2757  gnutls_x509_crt_deinit(request);
2758  return pgc;
2759 }
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...
static uint64_t etime
Expiration string converted to numeric value.
const char * name
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.
#define GNUNET_log(kind,...)
gnutls_x509_crt_t cert
The certificate.
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 2770 of file gnunet-gns-proxy.c.

Referenced by lookup_ssl_httpd().

2773 {
2774  /* do nothing */
2775 }
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 2785 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().

2786 {
2787  struct MhdHttpList *hd;
2788  struct ProxyGNSCertificate *pgc;
2789 
2790  if (NULL == domain)
2791  {
2792  GNUNET_break(0);
2793  return NULL;
2794  }
2795  for (hd = mhd_httpd_head; NULL != hd; hd = hd->next)
2796  if ((NULL != hd->domain) &&
2797  (0 == strcmp(hd->domain, domain)))
2798  return hd;
2800  "Starting fresh MHD HTTPS instance for domain `%s'\n",
2801  domain);
2802  pgc = generate_gns_certificate(domain);
2803  hd = GNUNET_new(struct MhdHttpList);
2804  hd->is_ssl = GNUNET_YES;
2805  hd->domain = GNUNET_strdup(domain);
2806  hd->proxy_cert = pgc;
2807  hd->daemon = MHD_start_daemon(MHD_USE_DEBUG | MHD_USE_SSL | MHD_USE_NO_LISTEN_SOCKET | MHD_ALLOW_SUSPEND_RESUME,
2808  0,
2809  NULL, NULL,
2810  &create_response, hd,
2811  MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int)16,
2812  MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, NULL,
2813  MHD_OPTION_NOTIFY_CONNECTION, &mhd_connection_cb, NULL,
2814  MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL,
2815  MHD_OPTION_EXTERNAL_LOGGER, &mhd_error_log_callback, NULL,
2816  MHD_OPTION_HTTPS_MEM_KEY, pgc->key,
2817  MHD_OPTION_HTTPS_MEM_CERT, pgc->cert,
2818  MHD_OPTION_END);
2819  if (NULL == hd->daemon)
2820  {
2821  GNUNET_free(pgc);
2822  GNUNET_free(hd);
2823  return NULL;
2824  }
2827  hd);
2828  return hd;
2829 }
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 2840 of file gnunet-gns-proxy.c.

References cleanup_s5r(), and Socks5Request::timeout_task.

Referenced by setup_data_transfer().

2841 {
2842  struct Socks5Request *s5r = cls;
2843 
2844  s5r->timeout_task = NULL;
2845  cleanup_s5r(s5r);
2846 }
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 2858 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().

2859 {
2860  struct MhdHttpList *hd;
2861  int fd;
2862  const struct sockaddr *addr;
2863  socklen_t len;
2864  char *domain;
2865 
2866  if (GNUNET_YES == s5r->is_tls)
2867  {
2868  GNUNET_asprintf(&domain,
2869  "%s",
2870  s5r->domain);
2871  hd = lookup_ssl_httpd(domain);
2872  if (NULL == hd)
2873  {
2875  _("Failed to start HTTPS server for `%s'\n"),
2876  s5r->domain);
2877  cleanup_s5r(s5r);
2878  GNUNET_free(domain);
2879  return;
2880  }
2881  }
2882  else
2883  {
2884  domain = NULL;
2885  GNUNET_assert(NULL != httpd);
2886  hd = httpd;
2887  }
2888  fd = GNUNET_NETWORK_get_fd(s5r->sock);
2889  addr = GNUNET_NETWORK_get_addr(s5r->sock);
2890  len = GNUNET_NETWORK_get_addrlen(s5r->sock);
2892  if (MHD_YES !=
2893  MHD_add_connection(hd->daemon,
2894  fd,
2895  addr,
2896  len))
2897  {
2899  _("Failed to pass client to MHD\n"));
2900  cleanup_s5r(s5r);
2901  GNUNET_free_non_null(domain);
2902  return;
2903  }
2904  s5r->hd = hd;
2905  schedule_httpd(hd);
2908  s5r);
2909  GNUNET_free_non_null(domain);
2910 }
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:1068
struct sockaddr * GNUNET_NETWORK_get_addr(const struct GNUNET_NETWORK_Handle *desc)
Return the sockaddr for this network handle.
Definition: network.c:1081
socklen_t GNUNET_NETWORK_get_addrlen(const struct GNUNET_NETWORK_Handle *desc)
Return sockaddr length for this network handle.
Definition: network.c:1094
#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:1237
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 2922 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().

2923 {
2924  struct Socks5Request *s5r = cls;
2925  ssize_t len;
2926 
2927  s5r->wtask = NULL;
2928  len = GNUNET_NETWORK_socket_send(s5r->sock,
2929  s5r->wbuf,
2930  s5r->wbuf_len);
2931  if (len <= 0)
2932  {
2933  /* write error: connection closed, shutdown, etc.; just clean up */
2935  "Write Error\n");
2936  cleanup_s5r(s5r);
2937  return;
2938  }
2939  memmove(s5r->wbuf,
2940  &s5r->wbuf[len],
2941  s5r->wbuf_len - len);
2942  s5r->wbuf_len -= len;
2943  if (s5r->wbuf_len > 0)
2944  {
2945  /* not done writing */
2946  s5r->wtask =
2948  s5r->sock,
2949  &do_write, s5r);
2950  return;
2951  }
2952 
2953  /* we're done writing, continue with state machine! */
2954 
2955  switch (s5r->state)
2956  {
2957  case SOCKS5_INIT:
2958  GNUNET_assert(0);
2959  break;
2960 
2961  case SOCKS5_REQUEST:
2962  GNUNET_assert(NULL != s5r->rtask);
2963  break;
2964 
2965  case SOCKS5_DATA_TRANSFER:
2966  setup_data_transfer(s5r);
2967  return;
2968 
2970  cleanup_s5r(s5r);
2971  return;
2972 
2973  default:
2974  GNUNET_break(0);
2975  break;
2976  }
2977 }
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:804
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:1537
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 2987 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().

2989 {
2990  struct Socks5ServerResponseMessage *s_resp;
2991 
2992  s_resp = (struct Socks5ServerResponseMessage *)&s5r->wbuf[s5r->wbuf_len];
2993  memset(s_resp, 0, sizeof(struct Socks5ServerResponseMessage));
2994  s_resp->version = SOCKS_VERSION_5;
2995  s_resp->reply = sc;
2997  if (NULL != s5r->wtask)
2998  s5r->wtask =
3000  s5r->sock,
3001  &do_write, s5r);
3002 }
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:1537
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 3011 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().

3012 {
3013  struct Socks5ServerResponseMessage *s_resp;
3014 
3015  s_resp = (struct Socks5ServerResponseMessage *)&s5r->wbuf[s5r->wbuf_len];
3016  s_resp->version = SOCKS_VERSION_5;
3018  s_resp->reserved = 0;
3019  s_resp->addr_type = SOCKS5_AT_IPV4;
3020  /* zero out IPv4 address and port */
3021  memset(&s_resp[1],
3022  0,
3023  sizeof(struct in_addr) + sizeof(uint16_t));
3024  s5r->wbuf_len += sizeof(struct Socks5ServerResponseMessage) +
3025  sizeof(struct in_addr) + sizeof(uint16_t);
3026  if (NULL == s5r->wtask)
3027  s5r->wtask =
3029  s5r->sock,
3030  &do_write, s5r);
3031 }
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:1537
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 3043 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().

3047 {
3048  struct Socks5Request *s5r = cls;
3049  const struct GNUNET_GNSRECORD_Data *r;
3050  int got_ip;
3051 
3052  s5r->gns_lookup = NULL;
3053  s5r->is_gns = tld;
3054  got_ip = GNUNET_NO;
3055  for (uint32_t i = 0; i < rd_count; i++)
3056  {
3057  r = &rd[i];
3058  switch (r->record_type)
3059  {
3061  {
3062  struct sockaddr_in *in;
3063 
3064  if (sizeof(struct in_addr) != r->data_size)
3065  {
3066  GNUNET_break_op(0);
3067  break;
3068  }
3069  if (GNUNET_YES == got_ip)
3070  break;
3071  if (GNUNET_OK !=
3072  GNUNET_NETWORK_test_pf(PF_INET))
3073  break;
3074  got_ip = GNUNET_YES;
3075  in = (struct sockaddr_in *)&s5r->destination_address;
3076  in->sin_family = AF_INET;
3077  GNUNET_memcpy(&in->sin_addr,
3078  r->data,
3079  r->data_size);
3080  in->sin_port = htons(s5r->port);
3081 #if HAVE_SOCKADDR_IN_SIN_LEN
3082  in->sin_len = sizeof(*in);
3083 #endif
3084  }
3085  break;
3086 
3088  {
3089  struct sockaddr_in6 *in;
3090 
3091  if (sizeof(struct in6_addr) != r->data_size)
3092  {
3093  GNUNET_break_op(0);
3094  break;
3095  }
3096  if (GNUNET_YES == got_ip)
3097  break;
3098  if (GNUNET_YES == disable_v6)
3099  break;
3100  if (GNUNET_OK !=
3101  GNUNET_NETWORK_test_pf(PF_INET6))
3102  break;
3103  /* FIXME: allow user to disable IPv6 per configuration option... */
3104  got_ip = GNUNET_YES;
3105  in = (struct sockaddr_in6 *)&s5r->destination_address;
3106  in->sin6_family = AF_INET6;
3107  GNUNET_memcpy(&in->sin6_addr,
3108  r->data,
3109  r->data_size);
3110  in->sin6_port = htons(s5r->port);
3111 #if HAVE_SOCKADDR_IN_SIN_LEN
3112  in->sin6_len = sizeof(*in);
3113 #endif
3114  }
3115  break;
3116 
3118  GNUNET_break(0); /* should have been translated within GNS */
3119  break;
3120 
3122  GNUNET_free_non_null(s5r->leho);
3123  s5r->leho = GNUNET_strndup(r->data,
3124  r->data_size);
3125  break;
3126 
3128  {
3129  const struct GNUNET_GNSRECORD_BoxRecord *box;
3130 
3131  if (r->data_size < sizeof(struct GNUNET_GNSRECORD_BoxRecord))
3132  {
3133  GNUNET_break_op(0);
3134  break;
3135  }
3136  box = r->data;
3137  if ((ntohl(box->record_type) != GNUNET_DNSPARSER_TYPE_TLSA) ||
3138  (ntohs(box->protocol) != IPPROTO_TCP) ||
3139  (ntohs(box->service) != s5r->port))
3140  break; /* BOX record does not apply */
3141  if (s5r->num_danes >= MAX_DANES)
3142  {
3143  GNUNET_break(0); /* MAX_DANES too small */
3144  break;
3145  }
3146  s5r->is_tls = GNUNET_YES; /* This should be TLS */
3147  s5r->dane_data_len[s5r->num_danes]
3148  = r->data_size - sizeof(struct GNUNET_GNSRECORD_BoxRecord);
3149  s5r->dane_data[s5r->num_danes]
3150  = GNUNET_memdup(&box[1],
3151  s5r->dane_data_len[s5r->num_danes]);
3152  s5r->num_danes++;
3153  break;
3154  }
3155 
3156  default:
3157  /* don't care */
3158  break;
3159  }
3160  }
3161  if ((GNUNET_YES != got_ip) &&
3162  (GNUNET_YES == tld))
3163  {
3165  "Name resolution failed to yield useful IP address.\n");
3168  return;
3169  }
3170  s5r->state = SOCKS5_DATA_TRANSFER;
3171  signal_socks_success(s5r);
3172 }
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:78
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 3182 of file gnunet-gns-proxy.c.

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

Referenced by do_s5r_read().

3184 {
3185  GNUNET_assert(len <= s5r->rbuf_len);
3186  memmove(s5r->rbuf,
3187  &s5r->rbuf[len],
3188  s5r->rbuf_len - len);
3189  s5r->rbuf_len -= len;
3190 }
#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 3199 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().

3200 {
3201  struct Socks5Request *s5r = cls;
3202  const struct Socks5ClientHelloMessage *c_hello;
3203  struct Socks5ServerHelloMessage *s_hello;
3204  const struct Socks5ClientRequestMessage *c_req;
3205  ssize_t rlen;
3206  size_t alen;
3207  const struct GNUNET_SCHEDULER_TaskContext *tc;
3208 
3209  s5r->rtask = NULL;
3211  if ((NULL != tc->read_ready) &&
3213  s5r->sock)))
3214  {
3215  rlen = GNUNET_NETWORK_socket_recv(s5r->sock,
3216  &s5r->rbuf[s5r->rbuf_len],
3217  sizeof(s5r->rbuf) - s5r->rbuf_len);
3218  if (rlen <= 0)
3219  {
3221  "socks5 client disconnected.\n");
3222  cleanup_s5r(s5r);
3223  return;
3224  }
3225  s5r->rbuf_len += rlen;
3226  }
3228  s5r->sock,
3229  &do_s5r_read, s5r);
3231  "Processing %zu bytes of socks data in state %d\n",
3232  s5r->rbuf_len,
3233  s5r->state);
3234  switch (s5r->state)
3235  {
3236  case SOCKS5_INIT:
3237  c_hello = (const struct Socks5ClientHelloMessage*)&s5r->rbuf;
3238  if ((s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)) ||
3239  (s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage) + c_hello->num_auth_methods))
3240  return; /* need more data */
3241  if (SOCKS_VERSION_5 != c_hello->version)
3242  {
3244  _("Unsupported socks version %d\n"),
3245  (int)c_hello->version);
3246  cleanup_s5r(s5r);
3247  return;
3248  }
3249  clear_from_s5r_rbuf(s5r,
3250  sizeof(struct Socks5ClientHelloMessage) + c_hello->num_auth_methods);
3251  GNUNET_assert(0 == s5r->wbuf_len);
3252  s_hello = (struct Socks5ServerHelloMessage *)&s5r->wbuf;
3253  s5r->wbuf_len = sizeof(struct Socks5ServerHelloMessage);
3254  s_hello->version = SOCKS_VERSION_5;
3255  s_hello->auth_method = SOCKS_AUTH_NONE;
3256  GNUNET_assert(NULL == s5r->wtask);
3258  s5r->sock,
3259  &do_write, s5r);
3260  s5r->state = SOCKS5_REQUEST;
3261  return;
3262 
3263  case SOCKS5_REQUEST:
3264  c_req = (const struct Socks5ClientRequestMessage *)&s5r->rbuf;
3265  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage))
3266  return;
3267  switch (c_req->command)
3268  {
3269  case SOCKS5_CMD_TCP_STREAM:
3270  /* handled below */
3271  break;
3272 
3273  default:
3275  _("Unsupported socks command %d\n"),
3276  (int)c_req->command);
3279  return;
3280  }
3281  switch (c_req->addr_type)
3282  {
3283  case SOCKS5_AT_IPV4:
3284  {
3285  const struct in_addr *v4 = (const struct in_addr *)&c_req[1];
3286  const uint16_t *port = (const uint16_t *)&v4[1];
3287  struct sockaddr_in *in;
3288 
3289  s5r->port = ntohs(*port);
3290  alen = sizeof(struct in_addr);
3291  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage) +
3292  alen + sizeof(uint16_t))
3293  return; /* need more data */
3294  in = (struct sockaddr_in *)&s5r->destination_address;
3295  in->sin_family = AF_INET;
3296  in->sin_addr = *v4;
3297  in->sin_port = *port;
3298 #if HAVE_SOCKADDR_IN_SIN_LEN
3299  in->sin_len = sizeof(*in);
3300 #endif
3301  s5r->state = SOCKS5_DATA_TRANSFER;
3302  }
3303  break;
3304 
3305  case SOCKS5_AT_IPV6:
3306  {
3307  const struct in6_addr *v6 = (const struct in6_addr *)&c_req[1];
3308  const uint16_t *port = (const uint16_t *)&v6[1];
3309  struct sockaddr_in6 *in;
3310 
3311  s5r->port = ntohs(*port);
3312  alen = sizeof(struct in6_addr);
3313  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage) +
3314  alen + sizeof(uint16_t))
3315  return; /* need more data */
3316  in = (struct sockaddr_in6 *)&s5r->destination_address;
3317  in->sin6_family = AF_INET6;
3318  in->sin6_addr = *v6;
3319  in->sin6_port = *port;
3320 #if HAVE_SOCKADDR_IN_SIN_LEN
3321  in->sin6_len = sizeof(*in);
3322 #endif
3323  s5r->state = SOCKS5_DATA_TRANSFER;
3324  }
3325  break;
3326 
3327  case SOCKS5_AT_DOMAINNAME:
3328  {
3329  const uint8_t *dom_len;
3330  const char *dom_name;
3331  const uint16_t *port;
3332 
3333  dom_len = (const uint8_t *)&c_req[1];
3334  alen = *dom_len + 1;
3335  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage) +
3336  alen + sizeof(uint16_t))
3337  return; /* need more data */
3338  dom_name = (const char *)&dom_len[1];
3339  port = (const uint16_t*)&dom_name[*dom_len];
3340  s5r->domain = GNUNET_strndup(dom_name,
3341  *dom_len);
3343  "Requested connection is to %s:%d\n",
3344  //(HTTPS_PORT == s5r->port) ? "s" : "",
3345  s5r->domain,
3346  ntohs(*port));
3347  s5r->state = SOCKS5_RESOLVING;
3348  s5r->port = ntohs(*port);
3349  s5r->is_tls = (HTTPS_PORT == s5r->port) ? GNUNET_YES : GNUNET_NO;
3351  s5r->domain,
3353  GNUNET_NO /* only cached */,
3355  s5r);
3356  break;
3357  }
3358 
3359  default:
3361  _("Unsupported socks address type %d\n"),
3362  (int)c_req->addr_type);
3365  return;
3366  }
3367  clear_from_s5r_rbuf(s5r,
3368  sizeof(struct Socks5ClientRequestMessage) +
3369  alen + sizeof(uint16_t));
3370  if (0 != s5r->rbuf_len)
3371  {
3372  /* read more bytes than healthy, why did the client send more!? */
3373  GNUNET_break_op(0);
3376  return;
3377  }
3378  if (SOCKS5_DATA_TRANSFER == s5r->state)
3379  {
3380  /* if we are not waiting for GNS resolution, signal success */
3381  signal_socks_success(s5r);
3382  }
3383  /* We are done reading right now */
3385  s5r->rtask = NULL;
3386  return;
3387 
3388  case SOCKS5_RESOLVING:
3389  GNUNET_assert(0);
3390  return;
3391 
3392  case SOCKS5_DATA_TRANSFER:
3393  GNUNET_assert(0);
3394  return;
3395 
3396  default:
3397  GNUNET_assert(0);
3398  return;
3399  }
3400 }
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:737
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:775
#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:410
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:240
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:1537
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:1467
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:1017
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:956
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 3410 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().

3411 {
3412  struct GNUNET_NETWORK_Handle *lsock = cls;
3413  struct GNUNET_NETWORK_Handle *s;
3414  struct Socks5Request *s5r;
3415 
3416  GNUNET_assert(NULL != lsock);
3417  if (lsock == lsock4)
3419  lsock,
3420  &do_accept,
3421  lsock);
3422  else if (lsock == lsock6)
3424  lsock,
3425  &do_accept,
3426  lsock);
3427  else
3428  GNUNET_assert(0);
3429  s = GNUNET_NETWORK_socket_accept(lsock,
3430  NULL,
3431  NULL);
3432  if (NULL == s)
3433  {
3435  "accept");
3436  return;
3437  }
3439  "Got an inbound connection, waiting for data\n");
3440  s5r = GNUNET_new(struct Socks5Request);
3442  s5r_tail,
3443  s5r);
3444  s5r->sock = s;
3445  s5r->state = SOCKS5_INIT;
3447  s5r->sock,
3448  &do_s5r_read,
3449  s5r);
3450 }
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:420
#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:46
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:1467
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 3462 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().

3463 {
3465  "Shutting down...\n");
3466  /* MHD requires resuming before destroying the daemons */
3467  for (struct Socks5Request *s5r = s5r_head;
3468  NULL != s5r;
3469  s5r = s5r->next)
3470  {
3471  if (s5r->suspended)
3472  {
3473  s5r->suspended = GNUNET_NO;
3474  MHD_resume_connection(s5r->con);
3475  }
3476  }
3477  while (NULL != mhd_httpd_head)
3479  while (NULL != s5r_head)
3481  if (NULL != lsock4)
3482  {
3484  lsock4 = NULL;
3485  }
3486  if (NULL != lsock6)
3487  {
3489  lsock6 = NULL;
3490  }
3491  if (NULL != curl_multi)
3492  {
3493  curl_multi_cleanup(curl_multi);
3494  curl_multi = NULL;
3495  }
3496  if (NULL != gns_handle)
3497  {
3499  gns_handle = NULL;
3500  }
3501  if (NULL != curl_download_task)
3502  {
3504  curl_download_task = NULL;
3505  }
3506  if (NULL != ltask4)
3507  {
3509  ltask4 = NULL;
3510  }
3511  if (NULL != ltask6)
3512  {
3514  ltask6 = NULL;
3515  }
3516  gnutls_x509_crt_deinit(proxy_ca.cert);
3517  gnutls_x509_privkey_deinit(proxy_ca.key);
3518  gnutls_global_deinit();
3519 }
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:282
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:548
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:956
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 3528 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().

3529 {
3530  struct GNUNET_NETWORK_Handle *ls;
3531  struct sockaddr_in sa4;
3532  int eno;
3533 
3534  memset(&sa4, 0, sizeof(sa4));
3535  sa4.sin_family = AF_INET;
3536  sa4.sin_port = htons(port);
3537  sa4.sin_addr.s_addr = address;
3538 #if HAVE_SOCKADDR_IN_SIN_LEN
3539  sa4.sin_len = sizeof(sa4);
3540 #endif
3541  ls = GNUNET_NETWORK_socket_create(AF_INET,
3542  SOCK_STREAM,
3543  0);
3544  if (NULL == ls)
3545  return NULL;
3546  if (GNUNET_OK !=
3548  (const struct sockaddr *)&sa4,
3549  sizeof(sa4)))
3550  {
3551  eno = errno;
3553  errno = eno;
3554  return NULL;
3555  }
3556  return ls;
3557 }
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:474
#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:46
int GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:548
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:900
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 3566 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().

3567 {
3568  struct GNUNET_NETWORK_Handle *ls;
3569  struct sockaddr_in6 sa6;
3570  int eno;
3571 
3572  memset(&sa6, 0, sizeof(sa6));
3573  sa6.sin6_family = AF_INET6;
3574  sa6.sin6_port = htons(port);
3575  sa6.sin6_addr = address6;
3576 #if HAVE_SOCKADDR_IN_SIN_LEN
3577  sa6.sin6_len = sizeof(sa6);
3578 #endif
3579  ls = GNUNET_NETWORK_socket_create(AF_INET6,
3580  SOCK_STREAM,
3581  0);
3582  if (NULL == ls)
3583  return NULL;
3584  if (GNUNET_OK !=
3586  (const struct sockaddr *)&sa6,
3587  sizeof(sa6)))
3588  {
3589  eno = errno;
3591  errno = eno;
3592  return NULL;
3593  }
3594  return ls;
3595 }
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:474
#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:46
int GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:548
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:900
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 3607 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().

3611 {
3612  char* cafile_cfg = NULL;
3613  char* cafile;
3614  char* addr_str;
3615  struct MhdHttpList *hd;
3616 
3617  cfg = c;
3618 
3619  /* Get address to bind to */
3621  "BIND_TO",
3622  &addr_str))
3623  {
3624  //No address specified
3626  "Don't know what to bind to...\n");
3627  GNUNET_free(addr_str);
3629  return;
3630  }
3631  if (1 != inet_pton(AF_INET, addr_str, &address))
3632  {
3634  "Unable to parse address %s\n",
3635  addr_str);
3636  GNUNET_free(addr_str);
3638  return;
3639  }
3640  GNUNET_free(addr_str);
3641  /* Get address to bind to */
3643  "BIND_TO6",
3644  &addr_str))
3645  {
3646  //No address specified
3648  "Don't know what to bind6 to...\n");
3649  GNUNET_free(addr_str);
3651  return;
3652  }
3653  if (1 != inet_pton(AF_INET6, addr_str, &address6))
3654  {
3656  "Unable to parse IPv6 address %s\n",
3657  addr_str);
3658  GNUNET_free(addr_str);
3660  return;
3661  }
3662  GNUNET_free(addr_str);
3663 
3664  if (NULL == (curl_multi = curl_multi_init()))
3665  {
3667  "Failed to create cURL multi handle!\n");
3668  return;
3669  }
3670  cafile = cafile_opt;
3671  if (NULL == cafile)
3672  {
3673  if (GNUNET_OK !=
3675  "gns-proxy",
3676  "PROXY_CACERT",
3677  &cafile_cfg))
3678  {
3680  "gns-proxy",
3681  "PROXY_CACERT");
3682  return;
3683  }
3684  cafile = cafile_cfg;
3685  }
3687  "Using `%s' as CA\n",
3688  cafile);
3689 
3690  gnutls_global_init();
3691  gnutls_x509_crt_init(&proxy_ca.cert);
3692  gnutls_x509_privkey_init(&proxy_ca.key);
3693 
3694  if ((GNUNET_OK !=
3696  cafile)) ||
3697  (GNUNET_OK !=
3699  cafile)))
3700  {
3702  _("Failed to load X.509 key and certificate from `%s'\n"),
3703  cafile);
3704  gnutls_x509_crt_deinit(proxy_ca.cert);
3705  gnutls_x509_privkey_deinit(proxy_ca.key);
3706  gnutls_global_deinit();
3707  GNUNET_free_non_null(cafile_cfg);
3708  return;
3709  }
3710  GNUNET_free_non_null(cafile_cfg);
3711  if (NULL == (gns_handle = GNUNET_GNS_connect(cfg)))
3712  {
3714  "Unable to connect to GNS!\n");
3715  gnutls_x509_crt_deinit(proxy_ca.cert);
3716  gnutls_x509_privkey_deinit(proxy_ca.key);
3717  gnutls_global_deinit();
3718  return;
3719  }
3721  NULL);
3722 
3723  /* Open listen socket for socks proxy */
3724  lsock6 = bind_v6();
3725  if (NULL == lsock6)
3726  {
3728  "bind");
3729  }
3730  else
3731  {
3732  if (GNUNET_OK !=
3734  5))
3735  {
3737  "listen");
3739  lsock6 = NULL;
3740  }
3741  else
3742  {
3744  lsock6,
3745  &do_accept,
3746  lsock6);
3747  }
3748  }
3749  lsock4 = bind_v4();
3750  if (NULL == lsock4)
3751  {
3753  "bind");
3754  }
3755  else
3756  {
3757  if (GNUNET_OK !=
3759  5))
3760  {
3762  "listen");
3764  lsock4 = NULL;
3765  }
3766  else
3767  {
3769  lsock4,
3770  &do_accept,
3771  lsock4);
3772  }
3773  }
3774  if ((NULL == lsock4) &&
3775  (NULL == lsock6))
3776  {
3778  return;
3779  }
3780  if (0 != curl_global_init(CURL_GLOBAL_WIN32))
3781  {
3783  "cURL global init failed!\n");