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

HTTP(S) proxy that rewrites URIs and fakes certificates 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 "gnunet_mhd_compat.h"
Include dependency graph for gnunet-gns-proxy.c:

Go to the source code of this file.

Data Structures

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

Macros

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

Enumerations

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

Functions

static void run_mhd_now (struct MhdHttpList *hd)
 Run MHD now, we have extra data ready for the callback. More...
 
static void cleanup_s5r (struct Socks5Request *s5r)
 Clean up s5r handles. More...
 
static void curl_download_prepare ()
 Ask cURL for the select() sets and schedule cURL operations. More...
 
static ssize_t mhd_content_cb (void *cls, uint64_t pos, char *buf, size_t max)
 Callback for MHD response generation. More...
 
static int check_ssl_certificate (struct Socks5Request *s5r)
 Check that the website has presented us with a valid X.509 certificate. More...
 
static size_t curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls)
 We're getting an HTTP response header from cURL. More...
 
static int create_mhd_response_from_s5r (struct Socks5Request *s5r)
 Create an MHD response object in s5r matching the information we got from curl. More...
 
static size_t curl_download_cb (void *ptr, size_t size, size_t nmemb, void *ctx)
 Handle response payload data from cURL. More...
 
static size_t curl_upload_cb (void *buf, size_t size, size_t nmemb, void *cls)
 cURL callback for uploaded (PUT/POST) data. More...
 
static void curl_task_download (void *cls)
 Task that is run when we are ready to receive more data from curl. More...
 
static int con_val_iter (void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
 Read HTTP request header field from the request. More...
 
static MHD_RESULT 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 (e.g. 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 certificates to make GNS work with legacy browsers.

Author
Martin Schanzenbach
Christian Grothoff

TODO:

Definition in file gnunet-gns-proxy.c.

Macro Definition Documentation

◆ GNUNET_GNS_PROXY_PORT

#define GNUNET_GNS_PROXY_PORT   7777

Default Socks5 listen port.

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

◆ MAX_HTTP_URI_LENGTH

#define MAX_HTTP_URI_LENGTH   2048

Maximum supported length for a URI.

Should die.

Deprecated:

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

◆ MAX_DANES

#define MAX_DANES   32

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

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

◆ IO_BUFFERSIZE

#define IO_BUFFERSIZE   CURL_MAX_WRITE_SIZE

Size of the buffer for the data upload / download.

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

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

◆ SOCKS_BUFFERSIZE

#define SOCKS_BUFFERSIZE   (256 + 32)

Size of the read/write buffers for Socks.

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

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

◆ HTTP_PORT

#define HTTP_PORT   80

Port for plaintext HTTP.

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

◆ HTTPS_PORT

#define HTTPS_PORT   443

Port for HTTPS.

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

◆ MAX_PEM_SIZE

#define MAX_PEM_SIZE   (10 * 1024)

Largest allowed size for a PEM certificate.

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

◆ MHD_CACHE_TIMEOUT

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

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

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

◆ HTTP_HANDSHAKE_TIMEOUT

#define HTTP_HANDSHAKE_TIMEOUT
Value:
#define GNUNET_TIME_UNIT_SECONDS
One second.

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.

◆ 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 GNUNET_log(kind,...)
#define _(String)
GNU gettext support macro.
Definition: platform.h:177

Log curl error.

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

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

◆ SOCKS_VERSION_5

#define SOCKS_VERSION_5   0x05

Which SOCKS version do we speak?

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

◆ SOCKS_AUTH_NONE

#define SOCKS_AUTH_NONE   0

Flag to set for 'no authentication'.

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

Enumeration Type Documentation

◆ Socks5Commands

Commands in Socks5.

Enumerator
SOCKS5_CMD_TCP_STREAM 

Establish TCP/IP stream.

SOCKS5_CMD_TCP_PORT 

Establish TCP port binding.

SOCKS5_CMD_UDP_PORT 

Establish UDP port binding.

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

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

◆ Socks5AddressType

Address types in Socks5.

Enumerator
SOCKS5_AT_IPV4 

IPv4 address.

SOCKS5_AT_DOMAINNAME 

IPv4 address.

SOCKS5_AT_IPV6 

IPv6 address.

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

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

◆ Socks5StatusCode

Status codes in Socks5 response.

Enumerator
SOCKS5_STATUS_REQUEST_GRANTED 
SOCKS5_STATUS_GENERAL_FAILURE 
SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE 
SOCKS5_STATUS_NETWORK_UNREACHABLE 
SOCKS5_STATUS_HOST_UNREACHABLE 
SOCKS5_STATUS_CONNECTION_REFUSED_BY_HOST 
SOCKS5_STATUS_TTL_EXPIRED 
SOCKS5_STATUS_COMMAND_NOT_SUPPORTED 
SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED 

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

184 {
194 };
@ SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE
@ SOCKS5_STATUS_CONNECTION_REFUSED_BY_HOST
@ SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED
@ SOCKS5_STATUS_HOST_UNREACHABLE
@ SOCKS5_STATUS_TTL_EXPIRED
@ SOCKS5_STATUS_GENERAL_FAILURE
@ SOCKS5_STATUS_COMMAND_NOT_SUPPORTED
@ SOCKS5_STATUS_REQUEST_GRANTED
@ SOCKS5_STATUS_NETWORK_UNREACHABLE

◆ SocksPhase

enum SocksPhase

The socks phases.

Enumerator
SOCKS5_INIT 

We're waiting to get the client hello.

SOCKS5_REQUEST 

We're waiting to get the initial request.

SOCKS5_RESOLVING 

We are currently resolving the destination.

SOCKS5_DATA_TRANSFER 

We're in transfer mode.

SOCKS5_WRITE_THEN_CLEANUP 

Finish writing the write buffer, then clean up.

SOCKS5_SOCKET_WITH_MHD 

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

SOCKS5_SOCKET_UPLOAD_STARTED 

We've started receiving upload data from MHD.

SOCKS5_SOCKET_UPLOAD_DONE 

We've finished receiving upload data from MHD.

SOCKS5_SOCKET_DOWNLOAD_STARTED 

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

SOCKS5_SOCKET_DOWNLOAD_DONE 

We've finished receiving download data from cURL.

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

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

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

2586 {
2587  if (NULL != hd->httpd_task)
2590  hd);
2591 }
static void do_httpd(void *cls)
Task run whenever HTTP server operations are pending.
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:1281
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:957
struct GNUNET_SCHEDULER_Task * httpd_task
The task ID.

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().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cleanup_s5r()

static void cleanup_s5r ( struct Socks5Request s5r)
static

Clean up s5r handles.

Parameters
s5rthe handle to destroy

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

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

References Socks5Request::con, Socks5Request::curl, curl_failure_response, curl_multi, Socks5Request::dane_data, Socks5Request::domain, Socks5Request::gns_lookup, GNUNET_CONTAINER_DLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, 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, s5r_head, s5r_tail, 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().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ curl_download_prepare()

static void curl_download_prepare ( )
static

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

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

1571 {
1572  CURLMcode mret;
1573  fd_set rs;
1574  fd_set ws;
1575  fd_set es;
1576  int max;
1577  struct GNUNET_NETWORK_FDSet *grs;
1578  struct GNUNET_NETWORK_FDSet *gws;
1579  long to;
1580  struct GNUNET_TIME_Relative rtime;
1581 
1583  "Scheduling CURL interaction\n");
1584  if (NULL != curl_download_task)
1585  {
1587  curl_download_task = NULL;
1588  }
1589  max = -1;
1590  FD_ZERO (&rs);
1591  FD_ZERO (&ws);
1592  FD_ZERO (&es);
1593  if (CURLM_OK != (mret = curl_multi_fdset (curl_multi,
1594  &rs,
1595  &ws,
1596  &es,
1597  &max)))
1598  {
1600  "%s failed at %s:%d: `%s'\n",
1601  "curl_multi_fdset", __FILE__, __LINE__,
1602  curl_multi_strerror (mret));
1603  return;
1604  }
1605  to = -1;
1606  GNUNET_break (CURLM_OK ==
1607  curl_multi_timeout (curl_multi,
1608  &to));
1609  if (-1 == to)
1611  else
1613  to);
1614  if (-1 != max)
1615  {
1616  grs = GNUNET_NETWORK_fdset_create ();
1617  gws = GNUNET_NETWORK_fdset_create ();
1619  &rs,
1620  max + 1);
1622  &ws,
1623  max + 1);
1626  rtime,
1627  grs,
1628  gws,
1630  curl_multi);
1633  }
1634  else
1635  {
1638  curl_multi);
1639  }
1640 }
static void curl_task_download(void *cls)
Task that is run when we are ready to receive more data from curl.
static struct GNUNET_SCHEDULER_Task * curl_download_task
The cURL download task (curl multi API).
@ GNUNET_SCHEDULER_PRIORITY_DEFAULT
Run with the default priority (normal P2P operations).
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_ERROR
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1193
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1209
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:1063
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:1826
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:1254
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
#define max(x, y)
collection of IO descriptors
Time for relative time used by GNUnet, in microseconds.

References curl_download_task, 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, GNUNET_TIME_UNIT_MILLISECONDS, and max.

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

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mhd_content_cb()

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

Callback for MHD response generation.

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

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

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

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

References buf, 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, max, 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().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_ssl_certificate()

static int check_ssl_certificate ( struct Socks5Request s5r)
static

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

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

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

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

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

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().

Here is the caller graph for this function:

◆ curl_check_hdr()

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

We're getting an HTTP response header from cURL.

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

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

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

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

References _, check_ssl_certificate(), cleanup(), Socks5Request::domain, GNUNET_asprintf(), GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, 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, size, Socks5Request::ssl_checked, HttpResponseHeader::type, and HttpResponseHeader::value.

Referenced by create_response().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_mhd_response_from_s5r()

static int create_mhd_response_from_s5r ( struct Socks5Request s5r)
static

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

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

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

1330 {
1331  long resp_code;
1332  double content_length;
1333 
1334  if (NULL != s5r->response)
1335  {
1337  "Response already set!\n");
1338  return GNUNET_SYSERR;
1339  }
1340 
1341  GNUNET_break (CURLE_OK ==
1342  curl_easy_getinfo (s5r->curl,
1343  CURLINFO_RESPONSE_CODE,
1344  &resp_code));
1345  GNUNET_break (CURLE_OK ==
1346  curl_easy_getinfo (s5r->curl,
1347  CURLINFO_CONTENT_LENGTH_DOWNLOAD,
1348  &content_length));
1350  "Creating MHD response with code %d and size %d for %s%s\n",
1351  (int) resp_code,
1352  (int) content_length,
1353  s5r->domain,
1354  s5r->url);
1355  s5r->response_code = resp_code;
1356  s5r->response = MHD_create_response_from_callback ((-1 == content_length)
1357  ? MHD_SIZE_UNKNOWN
1358  : content_length,
1359  IO_BUFFERSIZE,
1360  &mhd_content_cb,
1361  s5r,
1362  NULL);
1363  for (struct HttpResponseHeader *header = s5r->header_head;
1364  NULL != header;
1365  header = header->next)
1366  {
1367  if (0 == strcasecmp (header->type,
1368  MHD_HTTP_HEADER_CONTENT_LENGTH))
1369  continue; /* MHD won't let us mess with those, for good reason */
1370  if ((0 == strcasecmp (header->type,
1371  MHD_HTTP_HEADER_TRANSFER_ENCODING)) &&
1372  ((0 == strcasecmp (header->value,
1373  "identity")) ||
1374  (0 == strcasecmp (header->value,
1375  "chunked"))))
1376  continue; /* MHD won't let us mess with those, for good reason */
1377  if (MHD_YES !=
1378  MHD_add_response_header (s5r->response,
1379  header->type,
1380  header->value))
1381  {
1382  GNUNET_break (0);
1384  "Failed to add header `%s:%s'\n",
1385  header->type,
1386  header->value);
1387  }
1388  }
1389  /* force connection to be closed after each request, as we
1390  do not support HTTP pipelining (yet, FIXME!) */
1391  /*GNUNET_break (MHD_YES ==
1392  MHD_add_response_header (s5r->response,
1393  MHD_HTTP_HEADER_CONNECTION,
1394  "close"));*/
1395  MHD_resume_connection (s5r->con);
1396  s5r->suspended = GNUNET_NO;
1397  return GNUNET_OK;
1398 }
static ssize_t mhd_content_cb(void *cls, uint64_t pos, char *buf, size_t max)
Callback for MHD response generation.
#define IO_BUFFERSIZE
Size of the buffer for the data upload / download.
@ GNUNET_ERROR_TYPE_INFO
struct HttpResponseHeader * next
DLL.
unsigned int response_code
HTTP response code to give to MHD for the response.

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().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ curl_download_cb()

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

Handle response payload data from cURL.

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

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

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

1416 {
1417  struct Socks5Request *s5r = ctx;
1418  size_t total = size * nmemb;
1419 
1421  "Receiving %ux%u bytes for `%s%s' from cURL to download\n",
1422  (unsigned int) size,
1423  (unsigned int) nmemb,
1424  s5r->domain,
1425  s5r->url);
1426  if (NULL == s5r->response)
1429  if ((SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) &&
1430  (0 == s5r->io_len))
1431  {
1433  "Previous upload finished... starting DOWNLOAD.\n");
1435  }
1436  if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
1437  (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1438  {
1439  /* we're still not done with the upload, do not yet
1440  start the download, the IO buffer is still full
1441  with upload data. */
1443  "Pausing CURL download `%s%s', waiting for UPLOAD to finish\n",
1444  s5r->domain,
1445  s5r->url);
1446  s5r->curl_paused = GNUNET_YES;
1447  return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */
1448  }
1449  if (sizeof(s5r->io_buf) - s5r->io_len < total)
1450  {
1452  "Pausing CURL `%s%s' download, not enough space %llu %llu %llu\n",
1453  s5r->domain,
1454  s5r->url,
1455  (unsigned long long) sizeof(s5r->io_buf),
1456  (unsigned long long) s5r->io_len,
1457  (unsigned long long) total);
1458  s5r->curl_paused = GNUNET_YES;
1459  return CURL_WRITEFUNC_PAUSE; /* not enough space */
1460  }
1461  GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
1462  ptr,
1463  total);
1464  s5r->io_len += total;
1465  if (GNUNET_YES == s5r->suspended)
1466  {
1467  MHD_resume_connection (s5r->con);
1468  s5r->suspended = GNUNET_NO;
1469  }
1471  "Received %llu bytes of payload via cURL from %s\n",
1472  (unsigned long long) total,
1473  s5r->domain);
1474  if (s5r->io_len == total)
1475  run_mhd_now (s5r->hd);
1476  return total;
1477 }
static int create_mhd_response_from_s5r(struct Socks5Request *s5r)
Create an MHD response object in s5r matching the information we got from curl.
static void run_mhd_now(struct MhdHttpList *hd)
Run MHD now, we have extra data ready for the callback.
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
struct MhdHttpList * hd
MHD HTTP instance handling this request, NULL for none.

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(), size, SOCKS5_SOCKET_DOWNLOAD_STARTED, SOCKS5_SOCKET_UPLOAD_DONE, SOCKS5_SOCKET_UPLOAD_STARTED, Socks5Request::state, Socks5Request::suspended, and Socks5Request::url.

Referenced by create_response().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ curl_upload_cb()

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

cURL callback for uploaded (PUT/POST) data.

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

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

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

1495 {
1496  struct Socks5Request *s5r = cls;
1497  size_t len = size * nmemb;
1498  size_t to_copy;
1499 
1501  "Receiving %ux%u bytes for `%s%s' from cURL to upload\n",
1502  (unsigned int) size,
1503  (unsigned int) nmemb,
1504  s5r->domain,
1505  s5r->url);
1506 
1507  if ((0 == s5r->io_len) &&
1508  (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1509  {
1511  "Pausing CURL UPLOAD %s%s, need more data\n",
1512  s5r->domain,
1513  s5r->url);
1514  return CURL_READFUNC_PAUSE;
1515  }
1516  if ((0 == s5r->io_len) &&
1517  (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1518  {
1520  if (GNUNET_YES == s5r->curl_paused)
1521  {
1522  s5r->curl_paused = GNUNET_NO;
1523  curl_easy_pause (s5r->curl,
1524  CURLPAUSE_CONT);
1525  }
1527  "Completed CURL UPLOAD %s%s\n",
1528  s5r->domain,
1529  s5r->url);
1530  return 0; /* upload finished, can now download */
1531  }
1532  if ((SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) &&
1533  (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1534  {
1535  GNUNET_break (0);
1536  return CURL_READFUNC_ABORT;
1537  }
1538  to_copy = GNUNET_MIN (s5r->io_len,
1539  len);
1540  GNUNET_memcpy (buf,
1541  s5r->io_buf,
1542  to_copy);
1543  memmove (s5r->io_buf,
1544  &s5r->io_buf[to_copy],
1545  s5r->io_len - to_copy);
1546  s5r->io_len -= to_copy;
1547  if (s5r->io_len + to_copy == sizeof(s5r->io_buf))
1548  run_mhd_now (s5r->hd); /* got more space for upload now */
1549  return to_copy;
1550 }
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...

References buf, Socks5Request::curl, Socks5Request::curl_paused, 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(), size, SOCKS5_SOCKET_DOWNLOAD_STARTED, SOCKS5_SOCKET_UPLOAD_DONE, SOCKS5_SOCKET_UPLOAD_STARTED, Socks5Request::state, and Socks5Request::url.

Referenced by create_response().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ curl_task_download()

static void curl_task_download ( void *  cls)
static

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

Parameters
clsclosure
clsclosure, NULL

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

1650 {
1651  int running;
1652  int msgnum;
1653  struct CURLMsg *msg;
1654  CURLMcode mret;
1655  struct Socks5Request *s5r;
1656 
1657  curl_download_task = NULL;
1659  "Running CURL interaction\n");
1660  do
1661  {
1662  running = 0;
1663  mret = curl_multi_perform (curl_multi,
1664  &running);
1666  "Checking CURL multi status: %d\n",
1667  mret);
1668  while (NULL != (msg = curl_multi_info_read (curl_multi,
1669  &msgnum)))
1670  {
1671  GNUNET_break (CURLE_OK ==
1672  curl_easy_getinfo (msg->easy_handle,
1673  CURLINFO_PRIVATE,
1674  (char **) &s5r));
1675  if (NULL == s5r)
1676  {
1677  GNUNET_break (0);
1678  continue;
1679  }
1680  switch (msg->msg)
1681  {
1682  case CURLMSG_NONE:
1683  /* documentation says this is not used */
1684  GNUNET_break (0);
1685  break;
1686 
1687  case CURLMSG_DONE:
1688  switch (msg->data.result)
1689  {
1690  case CURLE_OK:
1691  case CURLE_GOT_NOTHING:
1693  "CURL download %s%s completed.\n",
1694  s5r->domain,
1695  s5r->url);
1696  if (NULL == s5r->response)
1697  {
1700  }
1702  if (GNUNET_YES == s5r->suspended)
1703  {
1704  MHD_resume_connection (s5r->con);
1705  s5r->suspended = GNUNET_NO;
1706  }
1707  run_mhd_now (s5r->hd);
1708  break;
1709 
1710  default:
1712  "Download curl %s%s failed: %s\n",
1713  s5r->domain,
1714  s5r->url,
1715  curl_easy_strerror (msg->data.result));
1716  /* FIXME: indicate error somehow? close MHD connection badly as well? */
1718  if (GNUNET_YES == s5r->suspended)
1719  {
1720  MHD_resume_connection (s5r->con);
1721  s5r->suspended = GNUNET_NO;
1722  }
1723  run_mhd_now (s5r->hd);
1724  break;
1725  }
1726  if (NULL == s5r->response)
1728  break;
1729 
1730  case CURLMSG_LAST:
1731  /* documentation says this is not used */
1732  GNUNET_break (0);
1733  break;
1734 
1735  default:
1736  /* unexpected status code */
1737  GNUNET_break (0);
1738  break;
1739  }
1740  }
1741  ;
1742  }
1743  while (mret == CURLM_CALL_MULTI_PERFORM);
1744  if (CURLM_OK != mret)
1746  "%s failed at %s:%d: `%s'\n",
1747  "curl_multi_perform", __FILE__, __LINE__,
1748  curl_multi_strerror (mret));
1749  if (0 == running)
1750  {
1752  "Suspending cURL multi loop, no more events pending\n");
1753  if (NULL != curl_download_task)
1754  {
1756  curl_download_task = NULL;
1757  }
1758  return; /* nothing more in progress */
1759  }
1761 }
struct GNUNET_MessageHeader * msg
Definition: 005.c:2

References create_mhd_response_from_s5r(), curl_download_prepare(), curl_download_task, 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().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ con_val_iter()

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

Read HTTP request header field from the request.

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

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

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

1785 {
1786  struct Socks5Request *s5r = cls;
1787  char *hdr;
1788 
1789  if ((0 == strcasecmp (MHD_HTTP_HEADER_HOST,
1790  key)) &&
1791  (NULL != s5r->leho))
1792  value = s5r->leho;
1793  GNUNET_asprintf (&hdr,
1794  "%s: %s",
1795  key,
1796  value);
1798  "Adding HEADER `%s' to HTTP request\n",
1799  hdr);
1800  s5r->headers = curl_slist_append (s5r->headers,
1801  hdr);
1802  GNUNET_free (hdr);
1803  return MHD_YES;
1804 }
struct GNUNET_HashCode key
The key used in the DHT.
static char * value
Value of the record to add/remove.

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

Referenced by create_response().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_response()

static MHD_RESULT 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 ("HTTP/1.1" for version 1.1, etc.)
upload_datathe data being uploaded (excluding HEADERS, for a POST that fits into memory and that is encoded with a supported encoding, the POST data will NOT be given in upload_data and is instead available as part of MHD_get_connection_values; very large POST data will be made available incrementally in upload_data)
upload_data_sizeset initially to the size of the upload_data provided; the method must update this value to the number of bytes NOT processed;
con_clspointer to location where we store the struct Request
Returns
#MHD_YES if the connection was handled successfully, #MHD_NO if the socket must be closed due to a serious error while handling the request

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

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

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

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().

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

2280 {
2281  struct Socks5Request *s5r = *con_cls;
2282 
2283  if (NULL == s5r)
2284  return;
2285  if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
2287  "MHD encountered error handling request: %d\n",
2288  toe);
2289  if (NULL != s5r->curl)
2290  {
2292  "Removing cURL handle (MHD interaction complete)\n");
2293  curl_multi_remove_handle (curl_multi,
2294  s5r->curl);
2295  curl_slist_free_all (s5r->headers);
2296  s5r->headers = NULL;
2297  curl_easy_reset (s5r->curl);
2298  s5r->rbuf_len = 0;
2299  s5r->wbuf_len = 0;
2300  s5r->io_len = 0;
2302  }
2303  if ((NULL != s5r->response) &&
2304  (curl_failure_response != s5r->response))
2305  MHD_destroy_response (s5r->response);
2306  for (struct HttpResponseHeader *header = s5r->header_head;
2307  NULL != header;
2308  header = s5r->header_head)
2309  {
2311  s5r->header_tail,
2312  header);
2313  GNUNET_free (header->type);
2314  GNUNET_free (header->value);
2315  GNUNET_free (header);
2316  }
2318  "Finished request for %s\n",
2319  s5r->url);
2320  GNUNET_free (s5r->url);
2322  s5r->url = NULL;
2323  s5r->response = NULL;
2324  *con_cls = NULL;
2325 }
size_t rbuf_len
Number of bytes already in read buffer.
size_t wbuf_len
Number of bytes already in write buffer.

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().

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

2342 {
2343  struct Socks5Request *s5r;
2344  const union MHD_ConnectionInfo *ci;
2345  int sock;
2346 
2347  switch (cnc)
2348  {
2349  case MHD_CONNECTION_NOTIFY_STARTED:
2350  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
2351  ci = MHD_get_connection_info (connection,
2352  MHD_CONNECTION_INFO_CONNECTION_FD);
2353  if (NULL == ci)
2354  {
2355  GNUNET_break (0);
2356  return;
2357  }
2358  sock = ci->connect_fd;
2359  for (s5r = s5r_head; NULL != s5r; s5r = s5r->next)
2360  {
2361  if (GNUNET_NETWORK_get_fd (s5r->sock) == sock)
2362  {
2364  "Context set...\n");
2365  s5r->ssl_checked = GNUNET_NO;
2366  *con_cls = s5r;
2367  break;
2368  }
2369  }
2370  break;
2371 
2372  case MHD_CONNECTION_NOTIFY_CLOSED:
2374  "Connection closed... cleaning up\n");
2375  s5r = *con_cls;
2376  if (NULL == s5r)
2377  {
2379  "Connection stale!\n");
2380  return;
2381  }
2382  cleanup_s5r (s5r);
2384  *con_cls = NULL;
2385  break;
2386 
2387  default:
2388  GNUNET_break (0);
2389  }
2390 }
static void cleanup_s5r(struct Socks5Request *s5r)
Clean up s5r handles.
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition: network.c:1023
struct Socks5Request * next
DLL.

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, s5r_head, Socks5Request::sock, and Socks5Request::ssl_checked.

Referenced by lookup_ssl_httpd(), and run().

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

2410 {
2411  struct Socks5Request *s5r;
2412  const union MHD_ConnectionInfo *ci;
2413 
2414  ci = MHD_get_connection_info (connection,
2415  MHD_CONNECTION_INFO_SOCKET_CONTEXT);
2416  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
2417  if (NULL == ci)
2418  {
2419  GNUNET_break (0);
2420  return NULL;
2421  }
2422  s5r = ci->socket_context;
2423  if (NULL != s5r->url)
2424  {
2425  GNUNET_break (0);
2426  return NULL;
2427  }
2428  s5r->url = GNUNET_strdup (url);
2429  if (NULL != s5r->timeout_task)
2430  {
2432  s5r->timeout_task = NULL;
2433  }
2435  return s5r;
2436 }

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().

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

2446 {
2449  hd);
2450  GNUNET_free (hd->domain);
2451  MHD_stop_daemon (hd->daemon);
2452  if (NULL != hd->httpd_task)
2453  {
2455  hd->httpd_task = NULL;
2456  }
2457  GNUNET_free (hd->proxy_cert);
2458  if (hd == httpd)
2459  httpd = NULL;
2460  GNUNET_free (hd);
2461 }
static struct MhdHttpList * mhd_httpd_tail
DLL for http/https daemons.
static struct MhdHttpList * httpd
Daemon for HTTP (we have one per X.509 certificate, and then one for all HTTP connections; this is th...
static struct MhdHttpList * mhd_httpd_head
DLL for http/https daemons.
struct ProxyGNSCertificate * proxy_cert
Optional proxy certificate used.
char * domain
the domain name to server (only important for TLS)
struct MHD_Daemon * daemon
The daemon handle.

References MhdHttpList::daemon, MhdHttpList::domain, GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_SCHEDULER_cancel(), httpd, MhdHttpList::httpd_task, mhd_httpd_head, mhd_httpd_tail, and MhdHttpList::proxy_cert.

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

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

2471 {
2472  struct MhdHttpList *hd = cls;
2473 
2474  hd->httpd_task = NULL;
2475  kill_httpd (hd);
2476 }
static void kill_httpd(struct MhdHttpList *hd)
Kill the given MHD daemon.
A structure for all running Httpds.

References MhdHttpList::httpd_task, and kill_httpd().

Referenced by schedule_httpd().

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

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

2570 {
2571  struct MhdHttpList *hd = cls;
2572 
2573  hd->httpd_task = NULL;
2574  MHD_run (hd->daemon);
2575  schedule_httpd (hd);
2576 }
static void schedule_httpd(struct MhdHttpList *hd)
Schedule MHD.

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

Referenced by run_mhd_now(), and schedule_httpd().

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

2497 {
2498  fd_set rs;
2499  fd_set ws;
2500  fd_set es;
2501  struct GNUNET_NETWORK_FDSet *wrs;
2502  struct GNUNET_NETWORK_FDSet *wws;
2503  int max;
2504  int haveto;
2505  MHD_UNSIGNED_LONG_LONG timeout;
2506  struct GNUNET_TIME_Relative tv;
2507 
2508  FD_ZERO (&rs);
2509  FD_ZERO (&ws);
2510  FD_ZERO (&es);
2511  max = -1;
2512  if (MHD_YES !=
2513  MHD_get_fdset (hd->daemon,
2514  &rs,
2515  &ws,
2516  &es,
2517  &max))
2518  {
2519  kill_httpd (hd);
2520  return;
2521  }
2522  haveto = MHD_get_timeout (hd->daemon,
2523  &timeout);
2524  if (MHD_YES == haveto)
2525  tv.rel_value_us = (uint64_t) timeout * 1000LL;
2526  else
2528  if (-1 != max)
2529  {
2530  wrs = GNUNET_NETWORK_fdset_create ();
2531  wws = GNUNET_NETWORK_fdset_create ();
2532  GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
2533  GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
2534  }
2535  else
2536  {
2537  wrs = NULL;
2538  wws = NULL;
2539  }
2540  if (NULL != hd->httpd_task)
2541  {
2543  hd->httpd_task = NULL;
2544  }
2545  if ((MHD_YES != haveto) &&
2546  (-1 == max) &&
2547  (hd != httpd))
2548  {
2549  /* daemon is idle, kill after timeout */
2551  &kill_httpd_task,
2552  hd);
2553  }
2554  else
2555  {
2556  hd->httpd_task =
2558  tv, wrs, wws,
2559  &do_httpd, hd);
2560  }
2561  if (NULL != wrs)
2563  if (NULL != wws)
2565 }
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
static void kill_httpd_task(void *cls)
Task run whenever HTTP server is idle for too long.
#define MHD_CACHE_TIMEOUT
After how long do we clean up unused MHD TLS instances?

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, httpd, MhdHttpList::httpd_task, kill_httpd(), kill_httpd_task(), max, MHD_CACHE_TIMEOUT, GNUNET_TIME_Relative::rel_value_us, and timeout.

Referenced by do_httpd(), and setup_data_transfer().

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

2604 {
2605  void *buffer;
2606  uint64_t fsize;
2607 
2608  if (GNUNET_OK !=
2610  &fsize,
2611  GNUNET_YES,
2612  GNUNET_YES))
2613  return NULL;
2614  if (fsize > MAX_PEM_SIZE)
2615  return NULL;
2616  *size = (unsigned int) fsize;
2617  buffer = GNUNET_malloc (*size);
2618  if (fsize !=
2620  buffer,
2621  (size_t) fsize))
2622  {
2623  GNUNET_free (buffer);
2624  return NULL;
2625  }
2626  return buffer;
2627 }
static char * filename
#define MAX_PEM_SIZE
Largest allowed size for a PEM certificate.
enum GNUNET_GenericReturnValue 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:222
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:664

References filename, GNUNET_DISK_file_size(), GNUNET_DISK_fn_read(), GNUNET_free, GNUNET_malloc, GNUNET_OK, GNUNET_YES, consensus-simulation::int, MAX_PEM_SIZE, and size.

Referenced by load_cert_from_file(), and load_key_from_file().

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

2640 {
2641  gnutls_datum_t key_data;
2642  int ret;
2643 
2644  key_data.data = load_file (keyfile,
2645  &key_data.size);
2646  if (NULL == key_data.data)
2647  return GNUNET_SYSERR;
2648  ret = gnutls_x509_privkey_import (key, &key_data,
2649  GNUTLS_X509_FMT_PEM);
2650  if (GNUTLS_E_SUCCESS != ret)
2651  {
2653  _ ("Unable to import private key from file `%s'\n"),
2654  keyfile);
2655  }
2656  GNUNET_free (key_data.data);
2657  return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2658 }
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static void * load_file(const char *filename, unsigned int *size)
Read file in filename.

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

Referenced by run().

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

2671 {
2672  gnutls_datum_t cert_data;
2673  int ret;
2674 
2675  cert_data.data = load_file (certfile,
2676  &cert_data.size);
2677  if (NULL == cert_data.data)
2678  return GNUNET_SYSERR;
2679  ret = gnutls_x509_crt_import (crt,
2680  &cert_data,
2681  GNUTLS_X509_FMT_PEM);
2682  if (GNUTLS_E_SUCCESS != ret)
2683  {
2685  _ ("Unable to import certificate from `%s'\n"),
2686  certfile);
2687  }
2688  GNUNET_free (cert_data.data);
2689  return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2690 }

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

Referenced by run().

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

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

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

Referenced by lookup_ssl_httpd().

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

2785 {
2786  /* do nothing */
2787 }

Referenced by lookup_ssl_httpd().

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

2798 {
2799  struct MhdHttpList *hd;
2800  struct ProxyGNSCertificate *pgc;
2801 
2802  if (NULL == domain)
2803  {
2804  GNUNET_break (0);
2805  return NULL;
2806  }
2807  for (hd = mhd_httpd_head; NULL != hd; hd = hd->next)
2808  if ((NULL != hd->domain) &&
2809  (0 == strcmp (hd->domain, domain)))
2810  return hd;
2812  "Starting fresh MHD HTTPS instance for domain `%s'\n",
2813  domain);
2814  pgc = generate_gns_certificate (domain);
2815  hd = GNUNET_new (struct MhdHttpList);
2816  hd->is_ssl = GNUNET_YES;
2817  hd->domain = GNUNET_strdup (domain);
2818  hd->proxy_cert = pgc;
2819  hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL
2820  | MHD_USE_NO_LISTEN_SOCKET
2821  | MHD_ALLOW_SUSPEND_RESUME,
2822  0,
2823  NULL, NULL,
2824  &create_response, hd,
2825  MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
2826  int) 16,
2827  MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
2828  NULL,
2829  MHD_OPTION_NOTIFY_CONNECTION,
2830  &mhd_connection_cb, NULL,
2831  MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
2832  NULL,
2833  MHD_OPTION_EXTERNAL_LOGGER,
2834  &mhd_error_log_callback, NULL,
2835  MHD_OPTION_HTTPS_MEM_KEY, pgc->key,
2836  MHD_OPTION_HTTPS_MEM_CERT, pgc->cert,
2837  MHD_OPTION_END);
2838  if (NULL == hd->daemon)
2839  {
2840  GNUNET_free (pgc);
2841  GNUNET_free (hd);
2842  return NULL;
2843  }
2846  hd);
2847  return hd;
2848 }
static void * mhd_log_callback(void *cls, const char *url, struct MHD_Connection *connection)
Function called when MHD first processes an incoming connection.
static MHD_RESULT 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.
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_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.
static struct ProxyGNSCertificate * generate_gns_certificate(const char *name)
Generate new certificate for specific name.
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.
struct MhdHttpList * next
DLL for httpds.
int is_ssl
is this an ssl daemon?

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_httpd_head, mhd_httpd_tail, mhd_log_callback(), MhdHttpList::next, and MhdHttpList::proxy_cert.

Referenced by setup_data_transfer().

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 (e.g.

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

Parameters
clsthe struct Socks5Request *

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

2860 {
2861  struct Socks5Request *s5r = cls;
2862 
2863  s5r->timeout_task = NULL;
2864  cleanup_s5r (s5r);
2865 }

References cleanup_s5r(), and Socks5Request::timeout_task.

Referenced by setup_data_transfer().

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

2878 {
2879  struct MhdHttpList *hd;
2880  int fd;
2881  const struct sockaddr *addr;
2882  socklen_t len;
2883  char *domain;
2884 
2885  if (GNUNET_YES == s5r->is_tls)
2886  {
2887  GNUNET_asprintf (&domain,
2888  "%s",
2889  s5r->domain);
2890  hd = lookup_ssl_httpd (domain);
2891  if (NULL == hd)
2892  {
2894  _ ("Failed to start HTTPS server for `%s'\n"),
2895  s5r->domain);
2896  cleanup_s5r (s5r);
2897  GNUNET_free (domain);
2898  return;
2899  }
2900  }
2901  else
2902  {
2903  domain = NULL;
2904  GNUNET_assert (NULL != httpd);
2905  hd = httpd;
2906  }
2907  fd = GNUNET_NETWORK_get_fd (s5r->sock);
2908  addr = GNUNET_NETWORK_get_addr (s5r->sock);
2911  if (MHD_YES !=
2912  MHD_add_connection (hd->daemon,
2913  fd,
2914  addr,
2915  len))
2916  {
2918  _ ("Failed to pass client to MHD\n"));
2919  cleanup_s5r (s5r);
2920  GNUNET_free (domain);
2921  return;
2922  }
2923  s5r->hd = hd;
2924  schedule_httpd (hd);
2927  s5r);
2928  GNUNET_free (domain);
2929 }
static struct MhdHttpList * lookup_ssl_httpd(const char *domain)
Lookup (or create) an TLS MHD instance for a particular domain.
#define HTTP_HANDSHAKE_TIMEOUT
After how long do we clean up Socks5 handles that failed to show any activity with their respective M...
static void timeout_s5r_handshake(void *cls)
Task run when a Socks5Request somehow fails to be associated with an MHD connection (e....
struct sockaddr * GNUNET_NETWORK_get_addr(const struct GNUNET_NETWORK_Handle *desc)
Return the sockaddr for this network handle.
Definition: network.c:1036
socklen_t GNUNET_NETWORK_get_addrlen(const struct GNUNET_NETWORK_Handle *desc)
Return sockaddr length for this network handle.
Definition: network.c:1049

References _, cleanup_s5r(), MhdHttpList::daemon, Socks5Request::domain, GNUNET_asprintf(), GNUNET_assert, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, 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().

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

2942 {
2943  struct Socks5Request *s5r = cls;
2944  ssize_t len;
2945 
2946  s5r->wtask = NULL;
2948  s5r->wbuf,
2949  s5r->wbuf_len);
2950  if (len <= 0)
2951  {
2952  /* write error: connection closed, shutdown, etc.; just clean up */
2954  "Write Error\n");
2955  cleanup_s5r (s5r);
2956  return;
2957  }
2958  memmove (s5r->wbuf,
2959  &s5r->wbuf[len],
2960  s5r->wbuf_len - len);
2961  s5r->wbuf_len -= len;
2962  if (s5r->wbuf_len > 0)
2963  {
2964  /* not done writing */
2965  s5r->wtask =
2967  s5r->sock,
2968  &do_write, s5r);
2969  return;
2970  }
2971 
2972  /* we're done writing, continue with state machine! */
2973 
2974  switch (s5r->state)
2975  {
2976  case SOCKS5_INIT:
2977  GNUNET_assert (0);
2978  break;
2979 
2980  case SOCKS5_REQUEST:
2981  GNUNET_assert (NULL != s5r->rtask);
2982  break;
2983 
2984  case SOCKS5_DATA_TRANSFER:
2985  setup_data_transfer (s5r);
2986  return;
2987 
2989  cleanup_s5r (s5r);
2990  return;
2991 
2992  default:
2993  GNUNET_break (0);
2994  break;
2995  }
2996 }
static void do_write(void *cls)
Write data from buffer to socks5 client, then continue with state machine.
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 des...
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:760
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:1573
char wbuf[(256+32)]
Write buffer.

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().

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

3008 {
3009  struct Socks5ServerResponseMessage *s_resp;
3010 
3011  GNUNET_break (0 == s5r->wbuf_len); /* Should happen first in any transmission, right? */
3013  sizeof(struct Socks5ServerResponseMessage));
3014  s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3015  memset (s_resp, 0, sizeof(struct Socks5ServerResponseMessage));
3016  s_resp->version = SOCKS_VERSION_5;
3017  s_resp->reply = sc;
3019  if (NULL != s5r->wtask)
3020  s5r->wtask =
3022  s5r->sock,
3023  &do_write, s5r);
3024 }
#define SOCKS_VERSION_5
Which SOCKS version do we speak?
#define SOCKS_BUFFERSIZE
Size of the read/write buffers for Socks.
static struct GNUNET_FS_SearchContext * sc
Definition: gnunet-search.c:84
Server response to client requests in Socks5 protocol.
uint8_t reply
Status code, an enum Socks5StatusCode
uint8_t version
Should be SOCKS_VERSION_5.

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

Referenced by do_s5r_read(), and handle_gns_result().

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

3034 {
3035  struct Socks5ServerResponseMessage *s_resp;
3036 
3037  s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3038  s_resp->version = SOCKS_VERSION_5;
3040  s_resp->reserved = 0;
3041  s_resp->addr_type = SOCKS5_AT_IPV4;
3042  /* zero out IPv4 address and port */
3043  memset (&s_resp[1],
3044  0,
3045  sizeof(struct in_addr) + sizeof(uint16_t));
3046  s5r->wbuf_len += sizeof(struct Socks5ServerResponseMessage)
3047  + sizeof(struct in_addr) + sizeof(uint16_t);
3048  if (NULL == s5r->wtask)
3049  s5r->wtask =
3051  s5r->sock,
3052  &do_write, s5r);
3053 }
uint8_t addr_type
Address type, an enum Socks5AddressType.
uint8_t reserved
Always zero.

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().

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

3069 {
3070  struct Socks5Request *s5r = cls;
3071  const struct GNUNET_GNSRECORD_Data *r;
3072  int got_ip;
3073 
3074  s5r->gns_lookup = NULL;
3075  s5r->is_gns = tld;
3076  got_ip = GNUNET_NO;
3077  for (uint32_t i = 0; i < rd_count; i++)
3078  {
3079  r = &rd[i];
3080  switch (r->record_type)
3081  {
3083  {
3084  struct sockaddr_in *in;
3085 
3086  if (sizeof(struct in_addr) != r->data_size)
3087  {
3088  GNUNET_break_op (0);
3089  break;
3090  }
3091  if (GNUNET_YES == got_ip)
3092  break;
3093  if (GNUNET_OK !=
3094  GNUNET_NETWORK_test_pf (PF_INET))
3095  break;
3096  got_ip = GNUNET_YES;
3097  in = (struct sockaddr_in *) &s5r->destination_address;
3098  in->sin_family = AF_INET;
3099  GNUNET_memcpy (&in->sin_addr,
3100  r->data,
3101  r->data_size);
3102  in->sin_port = htons (s5r->port);
3103 #if HAVE_SOCKADDR_IN_SIN_LEN
3104  in->sin_len = sizeof(*in);
3105 #endif
3106  }
3107  break;
3108 
3110  {
3111  struct sockaddr_in6 *in;
3112 
3113  if (sizeof(struct in6_addr) != r->data_size)
3114  {
3115  GNUNET_break_op (0);
3116  break;
3117  }
3118  if (GNUNET_YES == got_ip)
3119  break;
3120  if (GNUNET_YES == disable_v6)
3121  break;
3122  if (GNUNET_OK !=
3123  GNUNET_NETWORK_test_pf (PF_INET6))
3124  break;
3125  /* FIXME: allow user to disable IPv6 per configuration option... */
3126  got_ip = GNUNET_YES;
3127  in = (struct sockaddr_in6 *) &s5r->destination_address;
3128  in->sin6_family = AF_INET6;
3129  GNUNET_memcpy (&in->sin6_addr,
3130  r->data,
3131  r->data_size);
3132  in->sin6_port = htons (s5r->port);
3133 #if HAVE_SOCKADDR_IN_SIN_LEN
3134  in->sin6_len = sizeof(*in);
3135 #endif
3136  }
3137  break;
3138 
3140  GNUNET_break (0); /* should have been translated within GNS */
3141  break;
3142 
3144  GNUNET_free (s5r->leho);
3145  s5r->leho = GNUNET_strndup (r->data,
3146  r->data_size);
3147  break;
3148 
3150  {
3151  const struct GNUNET_GNSRECORD_BoxRecord *box;
3152 
3153  if (r->data_size < sizeof(struct GNUNET_GNSRECORD_BoxRecord))
3154  {
3155  GNUNET_break_op (0);
3156  break;
3157  }
3158  box = r->data;
3159  if ((ntohl (box->record_type) != GNUNET_DNSPARSER_TYPE_TLSA) ||
3160  (ntohs (box->protocol) != IPPROTO_TCP) ||
3161  (ntohs (box->service) != s5r->port))
3162  break; /* BOX record does not apply */
3163  if (s5r->num_danes >= MAX_DANES)
3164  {
3165  GNUNET_break (0); /* MAX_DANES too small */
3166  break;
3167  }
3168  s5r->is_tls = GNUNET_YES; /* This should be TLS */
3169  s5r->dane_data_len[s5r->num_danes]
3170  = r->data_size - sizeof(struct GNUNET_GNSRECORD_BoxRecord);
3171  s5r->dane_data[s5r->num_danes]
3172  = GNUNET_memdup (&box[1],
3173  s5r->dane_data_len[s5r->num_danes]);
3174  s5r->num_danes++;
3175  break;
3176  }
3177 
3178  default:
3179  /* don't care */
3180  break;
3181  }
3182  }
3183  if ((GNUNET_YES != got_ip) &&
3184  (GNUNET_YES == tld))
3185  {
3187  "Name resolution failed to yield useful IP address.\n");
3188  signal_socks_failure (s5r,
3190  return;
3191  }
3192  s5r->state = SOCKS5_DATA_TRANSFER;
3193  signal_socks_success (s5r);
3194 }
#define GNUNET_GNSRECORD_TYPE_BOX
Boxed records (see TLSA/SRV handling in GNS)
#define GNUNET_GNSRECORD_TYPE_VPN
VPN resolution.
#define GNUNET_GNSRECORD_TYPE_LEHO
legacy hostnames
static void signal_socks_success(struct Socks5Request *s5r)
Return a server response message indicating success.
static int disable_v6
Disable IPv6.
#define MAX_DANES
Maximum number of DANE records we support per domain name (and port and protocol).
static void signal_socks_failure(struct Socks5Request *s5r, enum Socks5StatusCode sc)
Return a server response message indicating a failure to the client.
#define GNUNET_DNSPARSER_TYPE_TLSA
#define GNUNET_DNSPARSER_TYPE_A
#define GNUNET_DNSPARSER_TYPE_AAAA
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
enum GNUNET_GenericReturnValue GNUNET_NETWORK_test_pf(int pf)
Test if the given protocol family is supported by this system.
Definition: network.c:79
Record type used to box up SRV and TLSA records.
uint32_t record_type
GNS record type of the boxed record.
uint16_t service
Service of the boxed record (aka port number), in NBO.
uint16_t protocol
Protocol of the boxed record (6 = TCP, 17 = UDP, etc.).
uint32_t record_type
Type of the GNS/DNS record.
const void * data
Binary value stored in the DNS record.
size_t data_size
Number of bytes in data.

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, 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().

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

3206 {
3207  GNUNET_assert (len <= s5r->rbuf_len);
3208  memmove (s5r->rbuf,
3209  &s5r->rbuf[len],
3210  s5r->rbuf_len - len);
3211  s5r->rbuf_len -= len;
3212 }
char rbuf[(256+32)]
Read buffer.

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

Referenced by do_s5r_read().

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

3222 {
3223  struct Socks5Request *s5r = cls;
3224  const struct Socks5ClientHelloMessage *c_hello;
3225  struct Socks5ServerHelloMessage *s_hello;
3226  const struct Socks5ClientRequestMessage *c_req;
3227  ssize_t rlen;
3228  size_t alen;
3229  const struct GNUNET_SCHEDULER_TaskContext *tc;
3230 
3231  s5r->rtask = NULL;
3233  if ((NULL != tc->read_ready) &&
3235  s5r->sock)))
3236  {
3237  rlen = GNUNET_NETWORK_socket_recv (s5r->sock,
3238  &s5r->rbuf[s5r->rbuf_len],
3239  sizeof(s5r->rbuf) - s5r->rbuf_len);
3240  if (rlen <= 0)
3241  {
3243  "socks5 client disconnected.\n");
3244  cleanup_s5r (s5r);
3245  return;
3246  }
3247  s5r->rbuf_len += rlen;
3248  }
3250  s5r->sock,
3251  &do_s5r_read, s5r);
3253  "Processing %zu bytes of socks data in state %d\n",
3254  s5r->rbuf_len,
3255  s5r->state);
3256  switch (s5r->state)
3257  {
3258  case SOCKS5_INIT:
3259  c_hello = (const struct Socks5ClientHelloMessage*) &s5r->rbuf;
3260  if ((s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)) ||
3261  (s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)
3262  + c_hello->num_auth_methods))
3263  return; /* need more data */
3264  if (SOCKS_VERSION_5 != c_hello->version)
3265  {
3267  _ ("Unsupported socks version %d\n"),
3268  (int) c_hello->version);
3269  cleanup_s5r (s5r);
3270  return;
3271  }
3272  clear_from_s5r_rbuf (s5r,
3273  sizeof(struct Socks5ClientHelloMessage)
3274  + c_hello->num_auth_methods);
3275  GNUNET_assert (0 == s5r->wbuf_len);
3276  s_hello = (struct Socks5ServerHelloMessage *) &s5r->wbuf;
3277  s5r->wbuf_len = sizeof(struct Socks5ServerHelloMessage);
3278  s_hello->version = SOCKS_VERSION_5;
3279  s_hello->auth_method = SOCKS_AUTH_NONE;
3280  GNUNET_assert (NULL == s5r->wtask);
3282  s5r->sock,
3283  &do_write, s5r);
3284  s5r->state = SOCKS5_REQUEST;
3285  return;
3286 
3287  case SOCKS5_REQUEST:
3288  c_req = (const struct Socks5ClientRequestMessage *) &s5r->rbuf;
3289  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage))
3290  return;
3291  switch (c_req->command)
3292  {
3293  case SOCKS5_CMD_TCP_STREAM:
3294  /* handled below */
3295  break;
3296 
3297  default:
3299  _ ("Unsupported socks command %d\n"),
3300  (int) c_req->command);
3301  signal_socks_failure (s5r,
3303  return;
3304  }
3305  switch (c_req->addr_type)
3306  {
3307  case SOCKS5_AT_IPV4:
3308  {
3309  const struct in_addr *v4 = (const struct in_addr *) &c_req[1];
3310  const uint16_t *port = (const uint16_t *) &v4[1];
3311  struct sockaddr_in *in;
3312 
3313  s5r->port = ntohs (*port);
3314  alen = sizeof(struct in_addr);
3315  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3316  + alen + sizeof(uint16_t))
3317  return; /* need more data */
3318  in = (struct sockaddr_in *) &s5r->destination_address;
3319  in->sin_family = AF_INET;
3320  in->sin_addr = *v4;
3321  in->sin_port = *port;
3322 #if HAVE_SOCKADDR_IN_SIN_LEN
3323  in->sin_len = sizeof(*in);
3324 #endif
3325  s5r->state = SOCKS5_DATA_TRANSFER;
3326  }
3327  break;
3328 
3329  case SOCKS5_AT_IPV6:
3330  {
3331  const struct in6_addr *v6 = (const struct in6_addr *) &c_req[1];
3332  const uint16_t *port = (const uint16_t *) &v6[1];
3333  struct sockaddr_in6 *in;
3334 
3335  s5r->port = ntohs (*port);
3336  alen = sizeof(struct in6_addr);
3337  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3338  + alen + sizeof(uint16_t))
3339  return; /* need more data */
3340  in = (struct sockaddr_in6 *) &s5r->destination_address;
3341  in->sin6_family = AF_INET6;
3342  in->sin6_addr = *v6;
3343  in->sin6_port = *port;
3344 #if HAVE_SOCKADDR_IN_SIN_LEN
3345  in->sin6_len = sizeof(*in);
3346 #endif
3347  s5r->state = SOCKS5_DATA_TRANSFER;
3348  }
3349  break;
3350 
3351  case SOCKS5_AT_DOMAINNAME:
3352  {
3353  const uint8_t *dom_len;
3354  const char *dom_name;
3355  const uint16_t *port;
3356 
3357  dom_len = (const uint8_t *) &c_req[1];
3358  alen = *dom_len + 1;
3359  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3360  + alen + sizeof(uint16_t))
3361  return; /* need more data */
3362  dom_name = (const char *) &dom_len[1];
3363  port = (const uint16_t *) &dom_name[*dom_len];
3364  s5r->domain = GNUNET_strndup (dom_name,
3365  *dom_len);
3367  "Requested connection is to %s:%d\n",
3368  // (HTTPS_PORT == s5r->port) ? "s" : "",
3369  s5r->domain,
3370  ntohs (*port));
3371  s5r->state = SOCKS5_RESOLVING;
3372  s5r->port = ntohs (*port);
3373  s5r->is_tls = (HTTPS_PORT == s5r->port) ? GNUNET_YES : GNUNET_NO;
3375  s5r->domain,
3377  GNUNET_GNS_LO_LOCAL_MASTER /* only cached */,
3379  s5r);
3380  break;
3381  }
3382 
3383  default:
3385  _ ("Unsupported socks address type %d\n"),
3386  (int) c_req->addr_type);
3387  signal_socks_failure (s5r,
3389  return;
3390  }
3391  clear_from_s5r_rbuf (s5r,
3392  sizeof(struct Socks5ClientRequestMessage)
3393  + alen + sizeof(uint16_t));
3394  if (0 != s5r->rbuf_len)
3395  {
3396  /* read more bytes than healthy, why did the client send more!? */
3397  GNUNET_break_op (0);
3398  signal_socks_failure (s5r,
3400  return;
3401  }
3402  if (SOCKS5_DATA_TRANSFER == s5r->state)
3403  {
3404  /* if we are not waiting for GNS resolution, signal success */
3405  signal_socks_success (s5r);
3406  }
3407  /* We are done reading right now */
3409  s5r->rtask = NULL;
3410  return;
3411 
3412  case SOCKS5_RESOLVING:
3413  GNUNET_assert (0);
3414  return;
3415 
3416  case SOCKS5_DATA_TRANSFER:
3417  GNUNET_assert (0);
3418  return;
3419 
3420  default:
3421  GNUNET_assert (0);
3422  return;
3423  }
3424 }
static void do_s5r_read(void *cls)
Read data from incoming Socks5 connection.
static struct GNUNET_GNS_Handle * gns_handle
Handle to the GNS service.
#define SOCKS_AUTH_NONE
Flag to set for 'no authentication'.
static void clear_from_s5r_rbuf(struct Socks5Request *s5r, size_t len)
Remove the first len bytes from the beginning of the read buffer.
#define HTTPS_PORT
Port for HTTPS.
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.
struct GNUNET_GNS_LookupWithTldRequest * GNUNET_GNS_lookup_with_tld(struct GNUNET_GNS_Handle *handle, const char *name, uint32_t type, enum GNUNET_GNS_LocalOptions options, GNUNET_GNS_LookupResultProcessor2 proc, void *proc_cls)
Perform an asynchronous lookup operation on the GNS, determining the zone using the TLD of the given ...
Definition: gns_tld_api.c:241
@ GNUNET_GNS_LO_LOCAL_MASTER
For the rightmost label, only look in the cache (it is our local namestore), for the others,...
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:731
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:972
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:1502
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:737
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:423
Context information passed to each scheduler task.
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 ...
Client hello in Socks5 protocol.
uint8_t version
Should be SOCKS_VERSION_5.
uint8_t num_auth_methods
How many authentication methods does the client support.
Client socks request in Socks5 protocol.
uint8_t command
Command code, we only uspport SOCKS5_CMD_TCP_STREAM.
uint8_t addr_type
Address type, an enum Socks5AddressType.
Server hello in Socks5 protocol.
uint8_t version
Should be SOCKS_VERSION_5.
uint8_t auth_method
Chosen authentication method, for us always SOCKS_AUTH_NONE, which skips the authentication step.

References _, Socks5ClientRequestMessage::addr_type, Socks5ServerHelloMessage::auth_method, cleanup_s5r(), clear_from_s5r_rbuf(), Socks5ClientRequestMessage::command, Socks5Request::destination_address, do_write(), Socks5Request::domain, gns_handle, Socks5Request::gns_lookup, GNUNET_assert, GNUNET_break_op, GNUNET_DNSPARSER_TYPE_A, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_GNS_LO_LOCAL_MASTER, 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().

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

3435 {
3436  struct GNUNET_NETWORK_Handle *lsock = cls;
3437  struct GNUNET_NETWORK_Handle *s;
3438  struct Socks5Request *s5r;
3439 
3440  GNUNET_assert (NULL != lsock);
3441  if (lsock == lsock4)
3443  lsock,
3444  &do_accept,
3445  lsock);
3446  else if (lsock == lsock6)
3448  lsock,
3449  &do_accept,
3450  lsock);
3451  else
3452  GNUNET_assert (0);
3453  s = GNUNET_NETWORK_socket_accept (lsock,
3454  NULL,
3455  NULL);
3456  if (NULL == s)
3457  {
3459  "accept");
3460  return;
3461  }
3463  "Got an inbound connection, waiting for data\n");
3464  s5r = GNUNET_new (struct Socks5Request);
3466  s5r_tail,
3467  s5r);
3468  s5r->sock = s;
3469  s5r->state = SOCKS5_INIT;
3471  s5r->sock,
3472  &do_s5r_read,
3473  s5r);
3474 }
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 void do_accept(void *cls)
Accept new incoming connections.
static struct GNUNET_SCHEDULER_Task * ltask6
The listen task ID for IPv6.
static struct GNUNET_SCHEDULER_Task * ltask4
The listen task ID for IPv4.
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
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:392
handle to a socket
Definition: network.c:53

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, lsock4, lsock6, ltask4, ltask6, Socks5Request::rtask, s5r_head, s5r_tail, Socks5Request::sock, SOCKS5_INIT, and Socks5Request::state.

Referenced by run().

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

3487 {
3489  "Shutting down...\n");
3490  /* MHD requires resuming before destroying the daemons */
3491  for (struct Socks5Request *s5r = s5r_head;
3492  NULL != s5r;
3493  s5r = s5r->next)
3494  {
3495  if (s5r->suspended)
3496  {
3497  s5r->suspended = GNUNET_NO;
3498  MHD_resume_connection (s5r->con);
3499  }
3500  }
3501  while (NULL != mhd_httpd_head)
3503  while (NULL != s5r_head)
3505  if (NULL != lsock4)
3506  {
3508  lsock4 = NULL;
3509  }
3510  if (NULL != lsock6)
3511  {
3513  lsock6 = NULL;
3514  }
3515  if (NULL != curl_multi)
3516  {
3517  curl_multi_cleanup (curl_multi);
3518  curl_multi = NULL;
3519  }
3520  if (NULL != gns_handle)
3521  {
3523  gns_handle = NULL;
3524  }
3525  if (NULL != curl_download_task)
3526  {
3528  curl_download_task = NULL;
3529  }
3530  if (NULL != ltask4)
3531  {
3533  ltask4 = NULL;
3534  }
3535  if (NULL != ltask6)
3536  {
3538  ltask6 = NULL;
3539  }
3540  gnutls_x509_crt_deinit (proxy_ca.cert);
3541  gnutls_x509_privkey_deinit (proxy_ca.key);
3542  gnutls_global_deinit ();
3543 }
void GNUNET_GNS_disconnect(struct GNUNET_GNS_Handle *handle)
Shutdown connection with the GNS service.
Definition: gns_api.c:290

References ProxyCA::cert, cleanup_s5r(), curl_download_task, curl_multi, gns_handle, GNUNET_ERROR_TYPE_INFO, GNUNET_GNS_disconnect(), GNUNET_log, GNUNET_NETWORK_socket_close(), GNUNET_NO, GNUNET_SCHEDULER_cancel(), ProxyCA::key, kill_httpd(), lsock4, lsock6, ltask4, ltask6, mhd_httpd_head, Socks5Request::next, proxy_ca, and s5r_head.

Referenced by run().

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

3553 {
3554  struct GNUNET_NETWORK_Handle *ls;
3555  struct sockaddr_in sa4;
3556  int eno;
3557 
3558  memset (&sa4, 0, sizeof(sa4));
3559  sa4.sin_family = AF_INET;
3560  sa4.sin_port = htons (port);
3561  sa4.sin_addr.s_addr = address;
3562 #if HAVE_SOCKADDR_IN_SIN_LEN
3563  sa4.sin_len = sizeof(sa4);
3564 #endif
3565  ls = GNUNET_NETWORK_socket_create (AF_INET,
3566  SOCK_STREAM,
3567  0);
3568  if (NULL == ls)
3569  return NULL;
3570  if (GNUNET_OK !=
3572  (const struct sockaddr *) &sa4,
3573  sizeof(sa4)))
3574  {
3575  eno = errno;
3577  errno = eno;
3578  return NULL;
3579  }
3580  return ls;
3581 }
static in_addr_t address
The address to bind to.
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition: gnunet-nat.c:85
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:855
enum GNUNET_GenericReturnValue 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:439

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

Referenced by run(), and setup_sockets().

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

3591 {
3592  struct GNUNET_NETWORK_Handle *ls;
3593  struct sockaddr_in6 sa6;
3594  int eno;
3595 
3596  memset (&sa6, 0, sizeof(sa6));
3597  sa6.sin6_family = AF_INET6;
3598  sa6.sin6_port = htons (port);
3599  sa6.sin6_addr = address6;
3600 #if HAVE_SOCKADDR_IN_SIN_LEN
3601  sa6.sin6_len = sizeof(sa6);
3602 #endif
3603  ls = GNUNET_NETWORK_socket_create (AF_INET6,
3604  SOCK_STREAM,
3605  0);
3606  if (NULL == ls)
3607  return NULL;
3608  if (GNUNET_OK !=
3610  (const struct sockaddr *) &sa6,
3611  sizeof(sa6)))
3612  {
3613  eno = errno;
3615  errno = eno;
3616  return NULL;
3617  }
3618  return ls;
3619 }
static struct in6_addr address6
The IPv6 address to bind to.

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

Referenced by run(), and setup_sockets().

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

3635 {
3636  char*cafile_cfg = NULL;
3637  char*cafile;
3638  char*addr_str;
3639  struct MhdHttpList *hd;
3640 
3641  cfg = c;
3642 
3643  /* Get address to bind to */
3645  "BIND_TO",
3646  &addr_str))
3647  {
3648  // No address specified
3650  "Don't know what to bind to...\n");
3651  GNUNET_free (addr_str);
3653  return;
3654  }
3655  if (1 != inet_pton (AF_INET, addr_str, &address))
3656  {
3658  "Unable to parse address %s\n",
3659  addr_str);
3660  GNUNET_free (addr_str);
3662  return;
3663  }
3664  GNUNET_free (addr_str);
3665  /* Get address to bind to */
3667  "BIND_TO6",
3668  &addr_str))
3669  {
3670  // No address specified
3672  "Don't know what to bind6 to...\n");
3673  GNUNET_free (addr_str);
3675  return;
3676  }
3677  if (1 != inet_pton (AF_INET6, addr_str, &address6))
3678  {
3680  "Unable to parse IPv6 address %s\n",
3681  addr_str);
3682  GNUNET_free (addr_str);
3684  return;
3685  }
3686  GNUNET_free (addr_str);
3687 
3688  if (NULL == (curl_multi = curl_multi_init ()))
3689  {
3691  "Failed to create cURL multi handle!\n");
3692  return;
3693  }
3694  cafile = cafile_opt;
3695  if (NULL == cafile)
3696  {
3697  if (GNUNET_OK !=
3699  "gns-proxy",
3700  "PROXY_CACERT",
3701  &cafile_cfg))
3702  {
3704  "gns-proxy",
3705  "PROXY_CACERT");
3706  return;
3707  }
3708  cafile = cafile_cfg;
3709  }
3711  "Using `%s' as CA\n",
3712  cafile);
3713 
3714  gnutls_global_init ();
3715  gnutls_x509_crt_init (&proxy_ca.cert);
3716  gnutls_x509_privkey_init (&proxy_ca.key);
3717 
3718  if ((GNUNET_OK !=
3720  cafile)) ||
3721  (GNUNET_OK !=
3723  cafile)))
3724  {
3726  _ ("Failed to load X.509 key and certificate from `%s'\n"),
3727  cafile);
3728  gnutls_x509_crt_deinit (proxy_ca.cert);
3729  gnutls_x509_privkey_deinit (proxy_ca.key);
3730  gnutls_global_deinit ();
3731  GNUNET_free (cafile_cfg);
3732  return;
3733  }
3734  GNUNET_free (cafile_cfg);
3735  if (NULL == (gns_handle = GNUNET_GNS_connect (cfg)))
3736  {
3738  "Unable to connect to GNS!\n");
3739  gnutls_x509_crt_deinit (proxy_ca.cert);
3740  gnutls_x509_privkey_deinit (proxy_ca.key);
3741  gnutls_global_deinit ();
3742  return;
3743  }
3745  NULL);
3746 
3747  /* Open listen socket for socks proxy */
3748  lsock6 = bind_v6 ();
3749  if (NULL == lsock6)
3750  {
3752  "bind");
3753  }
3754  else
3755  {
3756  if (GNUNET_OK !=
3758  5))
3759  {
3761  "listen");
3763  lsock6 = NULL;
3764  }
3765  else
3766  {
3768  lsock6,
3769  &do_accept,
3770  lsock6);
3771  }
3772  }
3773  lsock4 = bind_v4 ();
3774  if (NULL == lsock4)
3775  {
3777  "bind");
3778  }
3779  else
3780  {
3781  if (GNUNET_OK !=
3783  5))
3784  {
3786  "listen");
3788  lsock4 = NULL;
3789  }
3790  else
3791  {
3793  lsock4,
3794  &do_accept,
3795  lsock4);
3796  }
3797  }
3798  if ((NULL == lsock4) &&
3799  (NULL == lsock6))
3800  {
3802  return;
3803  }
3804  if (CURLSSLSET_OK != curl_global_sslset (CURLSSLBACKEND_GNUTLS,
3805  NULL,
3806  NULL))
3807  {
3809  "cURL does not support the GnuTLS backend\n");
3810 
3811  }
3812  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
3813  {
3815  "cURL global init failed!\n");
3817  return;
3818  }
3820  "Proxy listens on port %u\n",
3821  (unsigned int) port);
3822 
3823  /* start MHD daemon for HTTP */
3824  hd = GNUNET_new (struct MhdHttpList);
3825  hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
3826  | MHD_ALLOW_SUSPEND_RESUME,
3827  0,
3828  NULL, NULL,
3829  &create_response, hd,
3830  MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
3831  int) 16,
3832  MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
3833  NULL,
3834  MHD_OPTION_NOTIFY_CONNECTION,
3835  &mhd_connection_cb, NULL,
3836  MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
3837  NULL,
3838  MHD_OPTION_END);
3839  if (NULL == hd->daemon)
3840  {
3841  GNUNET_free (hd);
3843  return;
3844  }
3845  httpd = hd;
3848  hd);
3849 }
static struct GNUNET_NETWORK_Handle * bind_v6()
Create an IPv6 listen socket bound to our port.
static char * cafile_opt
The CA file (pem) to use for the proxy CA.
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
static int load_key_from_file(gnutls_x509_privkey_t key, const char *keyfile)
Load PEM key from file.
static void do_shutdown(void *cls)
Task run on shutdown.
static int load_cert_from_file(gnutls_x509_crt_t crt, const char *certfile)
Load cert from file.
static struct GNUNET_NETWORK_Handle * bind_v4()
Create an IPv4 listen socket bound to our port.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
struct GNUNET_GNS_Handle * GNUNET_GNS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Initialize the connection with the GNS service.
Definition: gns_api.c:268
void GNUNET_log_config_missing(enum GNUNET_ErrorType kind, const char *section, const char *option)
Log error message about missing configuration option.
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition: network.c:656
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:533
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1316

References _, address, address6, bind_v4(), bind_v6(), cafile_opt, ProxyCA::cert, cfg, create_response(), curl_multi, MhdHttpList::daemon, do_accept(), do_shutdown(), gns_handle, GNUNET_CONFIGURATION_get_value_filename(), GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, 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, httpd, ProxyCA::key, load_cert_from_file(), load_key_from_file(), lsock4, lsock6, ltask4, ltask6, mhd_completed_cb(), mhd_connection_cb(), mhd_httpd_head, mhd_httpd_tail, mhd_log_callback(), port, and proxy_ca.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char *const *  argv 
)

The main function for gnunet-gns-proxy.

Parameters
argcnumber of arguments from the command line
argvcommand line arguments
Returns
0 ok, 1 on error

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

3862 {
3865  "port",
3866  NULL,
3867  gettext_noop (
3868  "listen on specified port (default: 7777)"),
3869  &port),
3871  "authority",
3872  NULL,
3873  gettext_noop ("pem file to use as CA"),
3874  &cafile_opt),
3876  "disable-ivp6",
3877  gettext_noop ("disable use of IPv6"),
3878  &disable_v6),
3879 
3881  };
3882  static const char*page =
3883  "<html><head><title>gnunet-gns-proxy</title>"
3884  "</head><body>cURL fail</body></html>";
3885  int ret;
3886 
3887  if (GNUNET_OK !=
3888  GNUNET_STRINGS_get_utf8_args (argc, argv,
3889  &argc, &argv))
3890  return 2;
3891  GNUNET_log_setup ("gnunet-gns-proxy",
3892  "WARNING",
3893  NULL);
3895  = MHD_create_response_from_buffer (strlen (page),
3896  (void *) page,
3897  MHD_RESPMEM_PERSISTENT);
3898 
3899  ret =
3900  (GNUNET_OK ==
3901  GNUNET_PROGRAM_run (argc, argv,
3902  "gnunet-gns-proxy",
3903  _ ("GNUnet GNS proxy"),
3904  options,
3905  &run, NULL)) ? 0 : 1;
3906  MHD_destroy_response (curl_failure_response);
3907  GNUNET_free_nz ((char *) argv);
3908  return ret;
3909 }
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
#define gettext_noop(String)
Definition: gettext.h:69
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
Main function that will be run.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_flag(char shortName, const char *name, const char *description, int *val)
Allow user to specify a flag (which internally means setting an integer to 1/GNUNET_YES/GNUNET_OK.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_string(char shortName, const char *name, const char *argumentHelp, const char *description, char **str)
Allow user to specify a string.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_uint16(char shortName, const char *name, const char *argumentHelp, const char *description, uint16_t *val)
Allow user to specify an uint16_t.
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
#define GNUNET_free_nz(ptr)
Wrapper around free.
enum GNUNET_GenericReturnValue GNUNET_PROGRAM_run(int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls)
Run a standard GNUnet command startup sequence (initialize loggers and configuration,...
Definition: program.c:399
enum GNUNET_GenericReturnValue GNUNET_STRINGS_get_utf8_args(int argc, char *const *argv, int *u8argc, char *const **u8argv)
Returns utf-8 encoded arguments.
Definition: strings.c:1223
Definition of a command line option.

References _, cafile_opt, curl_failure_response, disable_v6, gettext_noop, GNUNET_free_nz, GNUNET_GETOPT_OPTION_END, GNUNET_GETOPT_option_flag(), GNUNET_GETOPT_option_string(), GNUNET_GETOPT_option_uint16(), GNUNET_log_setup(), GNUNET_OK, GNUNET_PROGRAM_run(), GNUNET_STRINGS_get_utf8_args(), options, port, ret, and run().

Here is the call graph for this function:

Variable Documentation

◆ address

in_addr_t address
static

The address to bind to.

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

Referenced by bind_v4(), and run().

◆ address6

struct in6_addr address6
static

The IPv6 address to bind to.

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

Referenced by bind_v6(), and run().

◆ port

uint16_t port = 7777
static

The port the proxy is running on (default 7777)

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

Referenced by bind_v4(), bind_v6(), create_response(), do_s5r_read(), main(), and run().

◆ cafile_opt

char* cafile_opt
static

The CA file (pem) to use for the proxy CA.

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

Referenced by main(), and run().

◆ lsock4

struct GNUNET_NETWORK_Handle* lsock4
static

The listen socket of the proxy for IPv4.

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

Referenced by do_accept(), do_shutdown(), and run().

◆ lsock6

struct GNUNET_NETWORK_Handle* lsock6
static

The listen socket of the proxy for IPv6.

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

Referenced by do_accept(), do_shutdown(), and run().

◆ ltask4

struct GNUNET_SCHEDULER_Task* ltask4
static

The listen task ID for IPv4.

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

Referenced by do_accept(), do_shutdown(), and run().

◆ ltask6

struct GNUNET_SCHEDULER_Task* ltask6
static

The listen task ID for IPv6.

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

Referenced by do_accept(), do_shutdown(), and run().

◆ curl_download_task

struct GNUNET_SCHEDULER_Task* curl_download_task
static

The cURL download task (curl multi API).

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

Referenced by curl_download_prepare(), curl_task_download(), and do_shutdown().

◆ curl_multi

CURLM* curl_multi
static

◆ gns_handle

struct GNUNET_GNS_Handle* gns_handle
static

Handle to the GNS service.

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

Referenced by do_s5r_read(), do_shutdown(), and run().

◆ disable_v6

int disable_v6
static

Disable IPv6.

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

Referenced by handle_gns_result(), and main().

◆ mhd_httpd_head

struct MhdHttpList* mhd_httpd_head
static

DLL for http/https daemons.

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

Referenced by do_shutdown(), kill_httpd(), lookup_ssl_httpd(), and run().

◆ mhd_httpd_tail

struct MhdHttpList* mhd_httpd_tail
static

DLL for http/https daemons.

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

Referenced by kill_httpd(), lookup_ssl_httpd(), and run().

◆ httpd

struct MhdHttpList* httpd
static

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).

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

Referenced by kill_httpd(), run(), schedule_httpd(), and setup_data_transfer().

◆ s5r_head

struct Socks5Request* s5r_head
static

DLL of active socks requests.

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

Referenced by cleanup_s5r(), do_accept(), do_shutdown(), and mhd_connection_cb().

◆ s5r_tail

struct Socks5Request* s5r_tail
static

DLL of active socks requests.

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

Referenced by cleanup_s5r(), and do_accept().

◆ proxy_ca

struct ProxyCA proxy_ca
static

The CA for X.509 certificate generation.

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

Referenced by do_shutdown(), generate_gns_certificate(), and run().

◆ curl_failure_response

struct MHD_Response* curl_failure_response
static

Response we return on cURL failures.

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

Referenced by cleanup_s5r(), create_response(), curl_task_download(), main(), and mhd_completed_cb().

◆ cfg

const struct GNUNET_CONFIGURATION_Handle* cfg
static

Our configuration.

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

Referenced by run().