GNUnet  0.19.4
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:

  • double-check queueing logic

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:484

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:178

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

2587 {
2588  if (NULL != hd->httpd_task)
2591  hd);
2592 }
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:1299
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:975
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
@ 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:565
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 1571 of file gnunet-gns-proxy.c.

1572 {
1573  CURLMcode mret;
1574  fd_set rs;
1575  fd_set ws;
1576  fd_set es;
1577  int max;
1578  struct GNUNET_NETWORK_FDSet *grs;
1579  struct GNUNET_NETWORK_FDSet *gws;
1580  long to;
1581  struct GNUNET_TIME_Relative rtime;
1582 
1584  "Scheduling CURL interaction\n");
1585  if (NULL != curl_download_task)
1586  {
1588  curl_download_task = NULL;
1589  }
1590  max = -1;
1591  FD_ZERO (&rs);
1592  FD_ZERO (&ws);
1593  FD_ZERO (&es);
1594  if (CURLM_OK != (mret = curl_multi_fdset (curl_multi,
1595  &rs,
1596  &ws,
1597  &es,
1598  &max)))
1599  {
1601  "%s failed at %s:%d: `%s'\n",
1602  "curl_multi_fdset", __FILE__, __LINE__,
1603  curl_multi_strerror (mret));
1604  return;
1605  }
1606  to = -1;
1607  GNUNET_break (CURLM_OK ==
1608  curl_multi_timeout (curl_multi,
1609  &to));
1610  if (-1 == to)
1612  else
1614  to);
1615  if (-1 != max)
1616  {
1617  grs = GNUNET_NETWORK_fdset_create ();
1618  gws = GNUNET_NETWORK_fdset_create ();
1620  &rs,
1621  max + 1);
1623  &ws,
1624  max + 1);
1627  rtime,
1628  grs,
1629  gws,
1631  curl_multi);
1634  }
1635  else
1636  {
1639  curl_multi);
1640  }
1641 }
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:1170
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1186
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:1040
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:1830
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:1272
#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
@ GNUNET_SYSERR
@ GNUNET_ERROR_TYPE_WARNING
static unsigned int size
Size of the "table".
Definition: peer.c:68
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  hdr_val[offset] = '\0';
1234  }
1235 
1236  new_location = NULL;
1237  if (0 == strcasecmp (MHD_HTTP_HEADER_TRANSFER_ENCODING,
1238  hdr_type))
1239  {
1240  /* Ignore transfer encoding, set automatically by MHD if required */
1241  goto cleanup;
1242  }
1243  if ((0 == strcasecmp (MHD_HTTP_HEADER_LOCATION,
1244  hdr_type)))
1245  {
1246  char *leho_host;
1247 
1248  GNUNET_asprintf (&leho_host,
1249  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1250  ? "http://%s"
1251  : "https://%s",
1252  s5r->leho);
1253  if (0 == strncmp (leho_host,
1254  hdr_val,
1255  strlen (leho_host)))
1256  {
1257  GNUNET_asprintf (&new_location,
1258  "%s%s%s",
1259  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1260  ? "http://"
1261  : "https://",
1262  s5r->domain,
1263  hdr_val + strlen (leho_host));
1264  hdr_val = new_location;
1265  }
1266  GNUNET_free (leho_host);
1267  }
1268  else if (0 == strcasecmp (MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
1269  hdr_type))
1270  {
1271  char *leho_host;
1272 
1273  GNUNET_asprintf (&leho_host,
1274  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1275  ? "http://%s"
1276  : "https://%s",
1277  s5r->leho);
1278  if (0 == strncmp (leho_host,
1279  hdr_val,
1280  strlen (leho_host)))
1281  {
1282  GNUNET_asprintf (&new_location,
1283  "%s%s",
1284  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1285  ? "http://"
1286  : "https://",
1287  s5r->domain);
1288  hdr_val = new_location;
1289  }
1290  GNUNET_free (leho_host);
1291  }
1292 
1293  /* MHD does not allow certain characters in values, remove those */
1294  if (NULL != (tok = strchr (hdr_val, '\n')))
1295  *tok = '\0';
1296  if (NULL != (tok = strchr (hdr_val, '\r')))
1297  *tok = '\0';
1298  if (NULL != (tok = strchr (hdr_val, '\t')))
1299  *tok = '\0';
1300  if (0 != strlen (hdr_val)) /* Rely in MHD to set those */
1301  {
1303  "Adding header %s: %s to MHD response\n",
1304  hdr_type,
1305  hdr_val);
1306  header = GNUNET_new (struct HttpResponseHeader);
1307  header->type = GNUNET_strdup (hdr_type);
1308  header->value = GNUNET_strdup (hdr_val);
1310  s5r->header_tail,
1311  header);
1312  }
1313  cleanup:
1314  GNUNET_free (ndup);
1315  GNUNET_free (new_cookie_hdr);
1316  GNUNET_free (new_location);
1317  return bytes;
1318 }
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 1330 of file gnunet-gns-proxy.c.

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

1417 {
1418  struct Socks5Request *s5r = ctx;
1419  size_t total = size * nmemb;
1420 
1422  "Receiving %ux%u bytes for `%s%s' from cURL to download\n",
1423  (unsigned int) size,
1424  (unsigned int) nmemb,
1425  s5r->domain,
1426  s5r->url);
1427  if (NULL == s5r->response)
1430  if ((SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) &&
1431  (0 == s5r->io_len))
1432  {
1434  "Previous upload finished... starting DOWNLOAD.\n");
1436  }
1437  if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
1438  (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1439  {
1440  /* we're still not done with the upload, do not yet
1441  start the download, the IO buffer is still full
1442  with upload data. */
1444  "Pausing CURL download `%s%s', waiting for UPLOAD to finish\n",
1445  s5r->domain,
1446  s5r->url);
1447  s5r->curl_paused = GNUNET_YES;
1448  return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */
1449  }
1450  if (sizeof(s5r->io_buf) - s5r->io_len < total)
1451  {
1453  "Pausing CURL `%s%s' download, not enough space %llu %llu %llu\n",
1454  s5r->domain,
1455  s5r->url,
1456  (unsigned long long) sizeof(s5r->io_buf),
1457  (unsigned long long) s5r->io_len,
1458  (unsigned long long) total);
1459  s5r->curl_paused = GNUNET_YES;
1460  return CURL_WRITEFUNC_PAUSE; /* not enough space */
1461  }
1462  GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
1463  ptr,
1464  total);
1465  s5r->io_len += total;
1466  if (GNUNET_YES == s5r->suspended)
1467  {
1468  MHD_resume_connection (s5r->con);
1469  s5r->suspended = GNUNET_NO;
1470  }
1472  "Received %llu bytes of payload via cURL from %s\n",
1473  (unsigned long long) total,
1474  s5r->domain);
1475  if (s5r->io_len == total)
1476  run_mhd_now (s5r->hd);
1477  return total;
1478 }
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 1492 of file gnunet-gns-proxy.c.

1496 {
1497  struct Socks5Request *s5r = cls;
1498  size_t len = size * nmemb;
1499  size_t to_copy;
1500 
1502  "Receiving %ux%u bytes for `%s%s' from cURL to upload\n",
1503  (unsigned int) size,
1504  (unsigned int) nmemb,
1505  s5r->domain,
1506  s5r->url);
1507 
1508  if ((0 == s5r->io_len) &&
1509  (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1510  {
1512  "Pausing CURL UPLOAD %s%s, need more data\n",
1513  s5r->domain,
1514  s5r->url);
1515  return CURL_READFUNC_PAUSE;
1516  }
1517  if ((0 == s5r->io_len) &&
1518  (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1519  {
1521  if (GNUNET_YES == s5r->curl_paused)
1522  {
1523  s5r->curl_paused = GNUNET_NO;
1524  curl_easy_pause (s5r->curl,
1525  CURLPAUSE_CONT);
1526  }
1528  "Completed CURL UPLOAD %s%s\n",
1529  s5r->domain,
1530  s5r->url);
1531  return 0; /* upload finished, can now download */
1532  }
1533  if ((SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) &&
1534  (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1535  {
1536  GNUNET_break (0);
1537  return CURL_READFUNC_ABORT;
1538  }
1539  to_copy = GNUNET_MIN (s5r->io_len,
1540  len);
1541  GNUNET_memcpy (buf,
1542  s5r->io_buf,
1543  to_copy);
1544  memmove (s5r->io_buf,
1545  &s5r->io_buf[to_copy],
1546  s5r->io_len - to_copy);
1547  s5r->io_len -= to_copy;
1548  if (s5r->io_len + to_copy == sizeof(s5r->io_buf))
1549  run_mhd_now (s5r->hd); /* got more space for upload now */
1550  return to_copy;
1551 }
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 1650 of file gnunet-gns-proxy.c.

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

1786 {
1787  struct Socks5Request *s5r = cls;
1788  char *hdr;
1789 
1790  if ((0 == strcasecmp (MHD_HTTP_HEADER_HOST,
1791  key)) &&
1792  (NULL != s5r->leho))
1793  value = s5r->leho;
1794  GNUNET_asprintf (&hdr,
1795  "%s: %s",
1796  key,
1797  value);
1799  "Adding HEADER `%s' to HTTP request\n",
1800  hdr);
1801  s5r->headers = curl_slist_append (s5r->headers,
1802  hdr);
1803  GNUNET_free (hdr);
1804  return MHD_YES;
1805 }
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 1832 of file gnunet-gns-proxy.c.

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

2281 {
2282  struct Socks5Request *s5r = *con_cls;
2283 
2284  if (NULL == s5r)
2285  return;
2286  if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
2288  "MHD encountered error handling request: %d\n",
2289  toe);
2290  if (NULL != s5r->curl)
2291  {
2293  "Removing cURL handle (MHD interaction complete)\n");
2294  curl_multi_remove_handle (curl_multi,
2295  s5r->curl);
2296  curl_slist_free_all (s5r->headers);
2297  s5r->headers = NULL;
2298  curl_easy_reset (s5r->curl);
2299  s5r->rbuf_len = 0;
2300  s5r->wbuf_len = 0;
2301  s5r->io_len = 0;
2303  }
2304  if ((NULL != s5r->response) &&
2305  (curl_failure_response != s5r->response))
2306  MHD_destroy_response (s5r->response);
2307  for (struct HttpResponseHeader *header = s5r->header_head;
2308  NULL != header;
2309  header = s5r->header_head)
2310  {
2312  s5r->header_tail,
2313  header);
2314  GNUNET_free (header->type);
2315  GNUNET_free (header->value);
2316  GNUNET_free (header);
2317  }
2319  "Finished request for %s\n",
2320  s5r->url);
2321  GNUNET_free (s5r->url);
2323  s5r->url = NULL;
2324  s5r->response = NULL;
2325  *con_cls = NULL;
2326 }
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 2339 of file gnunet-gns-proxy.c.

2343 {
2344  struct Socks5Request *s5r;
2345  const union MHD_ConnectionInfo *ci;
2346  int sock;
2347 
2348  switch (cnc)
2349  {
2350  case MHD_CONNECTION_NOTIFY_STARTED:
2351  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
2352  ci = MHD_get_connection_info (connection,
2353  MHD_CONNECTION_INFO_CONNECTION_FD);
2354  if (NULL == ci)
2355  {
2356  GNUNET_break (0);
2357  return;
2358  }
2359  sock = ci->connect_fd;
2360  for (s5r = s5r_head; NULL != s5r; s5r = s5r->next)
2361  {
2362  if (GNUNET_NETWORK_get_fd (s5r->sock) == sock)
2363  {
2365  "Context set...\n");
2366  s5r->ssl_checked = GNUNET_NO;
2367  *con_cls = s5r;
2368  break;
2369  }
2370  }
2371  break;
2372 
2373  case MHD_CONNECTION_NOTIFY_CLOSED:
2375  "Connection closed... cleaning up\n");
2376  s5r = *con_cls;
2377  if (NULL == s5r)
2378  {
2380  "Connection stale!\n");
2381  return;
2382  }
2383  cleanup_s5r (s5r);
2385  *con_cls = NULL;
2386  break;
2387 
2388  default:
2389  GNUNET_break (0);
2390  }
2391 }
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:1000
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 2408 of file gnunet-gns-proxy.c.

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

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

2447 {
2450  hd);
2451  GNUNET_free (hd->domain);
2452  MHD_stop_daemon (hd->daemon);
2453  if (NULL != hd->httpd_task)
2454  {
2456  hd->httpd_task = NULL;
2457  }
2458  GNUNET_free (hd->proxy_cert);
2459  if (hd == httpd)
2460  httpd = NULL;
2461  GNUNET_free (hd);
2462 }
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 2471 of file gnunet-gns-proxy.c.

2472 {
2473  struct MhdHttpList *hd = cls;
2474 
2475  hd->httpd_task = NULL;
2476  kill_httpd (hd);
2477 }
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 2570 of file gnunet-gns-proxy.c.

2571 {
2572  struct MhdHttpList *hd = cls;
2573 
2574  hd->httpd_task = NULL;
2575  MHD_run (hd->daemon);
2576  schedule_httpd (hd);
2577 }
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 2497 of file gnunet-gns-proxy.c.

2498 {
2499  fd_set rs;
2500  fd_set ws;
2501  fd_set es;
2502  struct GNUNET_NETWORK_FDSet *wrs;
2503  struct GNUNET_NETWORK_FDSet *wws;
2504  int max;
2505  int haveto;
2506  MHD_UNSIGNED_LONG_LONG timeout;
2507  struct GNUNET_TIME_Relative tv;
2508 
2509  FD_ZERO (&rs);
2510  FD_ZERO (&ws);
2511  FD_ZERO (&es);
2512  max = -1;
2513  if (MHD_YES !=
2514  MHD_get_fdset (hd->daemon,
2515  &rs,
2516  &ws,
2517  &es,
2518  &max))
2519  {
2520  kill_httpd (hd);
2521  return;
2522  }
2523  haveto = MHD_get_timeout (hd->daemon,
2524  &timeout);
2525  if (MHD_YES == haveto)
2526  tv.rel_value_us = (uint64_t) timeout * 1000LL;
2527  else
2529  if (-1 != max)
2530  {
2531  wrs = GNUNET_NETWORK_fdset_create ();
2532  wws = GNUNET_NETWORK_fdset_create ();
2533  GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
2534  GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
2535  }
2536  else
2537  {
2538  wrs = NULL;
2539  wws = NULL;
2540  }
2541  if (NULL != hd->httpd_task)
2542  {
2544  hd->httpd_task = NULL;
2545  }
2546  if ((MHD_YES != haveto) &&
2547  (-1 == max) &&
2548  (hd != httpd))
2549  {
2550  /* daemon is idle, kill after timeout */
2552  &kill_httpd_task,
2553  hd);
2554  }
2555  else
2556  {
2557  hd->httpd_task =
2559  tv, wrs, wws,
2560  &do_httpd, hd);
2561  }
2562  if (NULL != wrs)
2564  if (NULL != wws)
2566 }
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 2603 of file gnunet-gns-proxy.c.

2605 {
2606  void *buffer;
2607  uint64_t fsize;
2608 
2609  if (GNUNET_OK !=
2611  &fsize,
2612  GNUNET_YES,
2613  GNUNET_YES))
2614  return NULL;
2615  if (fsize > MAX_PEM_SIZE)
2616  return NULL;
2617  *size = (unsigned int) fsize;
2618  buffer = GNUNET_malloc (*size);
2619  if (fsize !=
2621  buffer,
2622  (size_t) fsize))
2623  {
2624  GNUNET_free (buffer);
2625  return NULL;
2626  }
2627  return buffer;
2628 }
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:221
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 2639 of file gnunet-gns-proxy.c.

2641 {
2642  gnutls_datum_t key_data;
2643  int ret;
2644 
2645  key_data.data = load_file (keyfile,
2646  &key_data.size);
2647  if (NULL == key_data.data)
2648  return GNUNET_SYSERR;
2649  ret = gnutls_x509_privkey_import (key, &key_data,
2650  GNUTLS_X509_FMT_PEM);
2651  if (GNUTLS_E_SUCCESS != ret)
2652  {
2654  _ ("Unable to import private key from file `%s'\n"),
2655  keyfile);
2656  }
2657  GNUNET_free (key_data.data);
2658  return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2659 }
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 2670 of file gnunet-gns-proxy.c.

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

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

2702 {
2703  unsigned int serial;
2704  size_t key_buf_size;
2705  size_t cert_buf_size;
2706  gnutls_x509_crt_t request;
2707  time_t etime;
2708  struct tm *tm_data;
2709  struct ProxyGNSCertificate *pgc;
2710 
2712  "Generating x.509 certificate for `%s'\n",
2713  name);
2714  GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_init (&request));
2715  GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_set_key (request,
2716  proxy_ca.key));
2717  pgc = GNUNET_new (struct ProxyGNSCertificate);
2718  gnutls_x509_crt_set_dn_by_oid (request,
2719  GNUTLS_OID_X520_COUNTRY_NAME,
2720  0,
2721  "ZZ",
2722  strlen ("ZZ"));
2723  gnutls_x509_crt_set_dn_by_oid (request,
2724  GNUTLS_OID_X520_ORGANIZATION_NAME,
2725  0,
2726  "GNU Name System",
2727  strlen ("GNU Name System"));
2728  gnutls_x509_crt_set_dn_by_oid (request,
2729  GNUTLS_OID_X520_COMMON_NAME,
2730  0,
2731  name,
2732  strlen (name));
2733  gnutls_x509_crt_set_subject_alternative_name (request,
2734  GNUTLS_SAN_DNSNAME,
2735  name);
2736  GNUNET_break (GNUTLS_E_SUCCESS ==
2737  gnutls_x509_crt_set_version (request,
2738  3));
2739  gnutls_rnd (GNUTLS_RND_NONCE,
2740  &serial,
2741  sizeof(serial));
2742  gnutls_x509_crt_set_serial (request,
2743  &serial,
2744  sizeof(serial));
2745  etime = time (NULL);
2746  tm_data = localtime (&etime);
2747  tm_data->tm_hour--;
2748  etime = mktime (tm_data);
2749  gnutls_x509_crt_set_activation_time (request,
2750  etime);
2751  tm_data->tm_year++;
2752  etime = mktime (tm_data);
2753  gnutls_x509_crt_set_expiration_time (request,
2754  etime);
2755  gnutls_x509_crt_sign2 (request,
2756  proxy_ca.cert,
2757  proxy_ca.key,
2758  GNUTLS_DIG_SHA512,
2759  0);
2760  key_buf_size = sizeof(pgc->key);
2761  cert_buf_size = sizeof(pgc->cert);
2762  gnutls_x509_crt_export (request,
2763  GNUTLS_X509_FMT_PEM,
2764  pgc->cert,
2765  &cert_buf_size);
2766  gnutls_x509_privkey_export (proxy_ca.key,
2767  GNUTLS_X509_FMT_PEM,
2768  pgc->key,
2769  &key_buf_size);
2770  gnutls_x509_crt_deinit (request);
2771  return pgc;
2772 }
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:40
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 2783 of file gnunet-gns-proxy.c.

2786 {
2787  /* do nothing */
2788 }

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

2799 {
2800  struct MhdHttpList *hd;
2801  struct ProxyGNSCertificate *pgc;
2802 
2803  if (NULL == domain)
2804  {
2805  GNUNET_break (0);
2806  return NULL;
2807  }
2808  for (hd = mhd_httpd_head; NULL != hd; hd = hd->next)
2809  if ((NULL != hd->domain) &&
2810  (0 == strcmp (hd->domain, domain)))
2811  return hd;
2813  "Starting fresh MHD HTTPS instance for domain `%s'\n",
2814  domain);
2815  pgc = generate_gns_certificate (domain);
2816  hd = GNUNET_new (struct MhdHttpList);
2817  hd->is_ssl = GNUNET_YES;
2818  hd->domain = GNUNET_strdup (domain);
2819  hd->proxy_cert = pgc;
2820  hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL
2821  | MHD_USE_NO_LISTEN_SOCKET
2822  | MHD_ALLOW_SUSPEND_RESUME,
2823  0,
2824  NULL, NULL,
2825  &create_response, hd,
2826  MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
2827  int) 16,
2828  MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
2829  NULL,
2830  MHD_OPTION_NOTIFY_CONNECTION,
2831  &mhd_connection_cb, NULL,
2832  MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
2833  NULL,
2834  MHD_OPTION_EXTERNAL_LOGGER,
2835  &mhd_error_log_callback, NULL,
2836  MHD_OPTION_HTTPS_MEM_KEY, pgc->key,
2837  MHD_OPTION_HTTPS_MEM_CERT, pgc->cert,
2838  MHD_OPTION_END);
2839  if (NULL == hd->daemon)
2840  {
2841  GNUNET_free (pgc);
2842  GNUNET_free (hd);
2843  return NULL;
2844  }
2847  hd);
2848  return hd;
2849 }
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 2860 of file gnunet-gns-proxy.c.

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

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

2879 {
2880  struct MhdHttpList *hd;
2881  int fd;
2882  const struct sockaddr *addr;
2883  socklen_t len;
2884  char *domain;
2885 
2886  if (GNUNET_YES == s5r->is_tls)
2887  {
2888  GNUNET_asprintf (&domain,
2889  "%s",
2890  s5r->domain);
2891  hd = lookup_ssl_httpd (domain);
2892  if (NULL == hd)
2893  {
2895  _ ("Failed to start HTTPS server for `%s'\n"),
2896  s5r->domain);
2897  cleanup_s5r (s5r);
2898  GNUNET_free (domain);
2899  return;
2900  }
2901  }
2902  else
2903  {
2904  domain = NULL;
2905  GNUNET_assert (NULL != httpd);
2906  hd = httpd;
2907  }
2908  fd = GNUNET_NETWORK_get_fd (s5r->sock);
2909  addr = GNUNET_NETWORK_get_addr (s5r->sock);
2912  if (MHD_YES !=
2913  MHD_add_connection (hd->daemon,
2914  fd,
2915  addr,
2916  len))
2917  {
2919  _ ("Failed to pass client to MHD\n"));
2920  cleanup_s5r (s5r);
2921  GNUNET_free (domain);
2922  return;
2923  }
2924  s5r->hd = hd;
2925  schedule_httpd (hd);
2928  s5r);
2929  GNUNET_free (domain);
2930 }
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:1013
socklen_t GNUNET_NETWORK_get_addrlen(const struct GNUNET_NETWORK_Handle *desc)
Return sockaddr length for this network handle.
Definition: network.c:1026

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

2943 {
2944  struct Socks5Request *s5r = cls;
2945  ssize_t len;
2946 
2947  s5r->wtask = NULL;
2949  s5r->wbuf,
2950  s5r->wbuf_len);
2951  if (len <= 0)
2952  {
2953  /* write error: connection closed, shutdown, etc.; just clean up */
2955  "Write Error\n");
2956  cleanup_s5r (s5r);
2957  return;
2958  }
2959  memmove (s5r->wbuf,
2960  &s5r->wbuf[len],
2961  s5r->wbuf_len - len);
2962  s5r->wbuf_len -= len;
2963  if (s5r->wbuf_len > 0)
2964  {
2965  /* not done writing */
2966  s5r->wtask =
2968  s5r->sock,
2969  &do_write, s5r);
2970  return;
2971  }
2972 
2973  /* we're done writing, continue with state machine! */
2974 
2975  switch (s5r->state)
2976  {
2977  case SOCKS5_INIT:
2978  GNUNET_assert (0);
2979  break;
2980 
2981  case SOCKS5_REQUEST:
2982  GNUNET_assert (NULL != s5r->rtask);
2983  break;
2984 
2985  case SOCKS5_DATA_TRANSFER:
2986  setup_data_transfer (s5r);
2987  return;
2988 
2990  cleanup_s5r (s5r);
2991  return;
2992 
2993  default:
2994  GNUNET_break (0);
2995  break;
2996  }
2997 }
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:737
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:1577
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 3007 of file gnunet-gns-proxy.c.

3009 {
3010  struct Socks5ServerResponseMessage *s_resp;
3011 
3012  GNUNET_break (0 == s5r->wbuf_len); /* Should happen first in any transmission, right? */
3014  sizeof(struct Socks5ServerResponseMessage));
3015  s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3016  memset (s_resp, 0, sizeof(struct Socks5ServerResponseMessage));
3017  s_resp->version = SOCKS_VERSION_5;
3018  s_resp->reply = sc;
3020  if (NULL != s5r->wtask)
3021  s5r->wtask =
3023  s5r->sock,
3024  &do_write, s5r);
3025 }
#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:87
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 3034 of file gnunet-gns-proxy.c.

3035 {
3036  struct Socks5ServerResponseMessage *s_resp;
3037 
3038  s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3039  s_resp->version = SOCKS_VERSION_5;
3041  s_resp->reserved = 0;
3042  s_resp->addr_type = SOCKS5_AT_IPV4;
3043  /* zero out IPv4 address and port */
3044  memset (&s_resp[1],
3045  0,
3046  sizeof(struct in_addr) + sizeof(uint16_t));
3047  s5r->wbuf_len += sizeof(struct Socks5ServerResponseMessage)
3048  + sizeof(struct in_addr) + sizeof(uint16_t);
3049  if (NULL == s5r->wtask)
3050  s5r->wtask =
3052  s5r->sock,
3053  &do_write, s5r);
3054 }
uint8_t 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 3066 of file gnunet-gns-proxy.c.

3070 {
3071  struct Socks5Request *s5r = cls;
3072  const struct GNUNET_GNSRECORD_Data *r;
3073  int got_ip;
3074 
3075  s5r->gns_lookup = NULL;
3076  s5r->is_gns = tld;
3077  got_ip = GNUNET_NO;
3078  for (uint32_t i = 0; i < rd_count; i++)
3079  {
3080  r = &rd[i];
3081  switch (r->record_type)
3082  {
3084  {
3085  struct sockaddr_in *in;
3086 
3087  if (sizeof(struct in_addr) != r->data_size)
3088  {
3089  GNUNET_break_op (0);
3090  break;
3091  }
3092  if (GNUNET_YES == got_ip)
3093  break;
3094  if (GNUNET_OK !=
3095  GNUNET_NETWORK_test_pf (PF_INET))
3096  break;
3097  got_ip = GNUNET_YES;
3098  in = (struct sockaddr_in *) &s5r->destination_address;
3099  in->sin_family = AF_INET;
3100  GNUNET_memcpy (&in->sin_addr,
3101  r->data,
3102  r->data_size);
3103  in->sin_port = htons (s5r->port);
3104 #if HAVE_SOCKADDR_IN_SIN_LEN
3105  in->sin_len = sizeof(*in);
3106 #endif
3107  }
3108  break;
3109 
3111  {
3112  struct sockaddr_in6 *in;
3113 
3114  if (sizeof(struct in6_addr) != r->data_size)
3115  {
3116  GNUNET_break_op (0);
3117  break;
3118  }
3119  if (GNUNET_YES == got_ip)
3120  break;
3121  if (GNUNET_YES == disable_v6)
3122  break;
3123  if (GNUNET_OK !=
3124  GNUNET_NETWORK_test_pf (PF_INET6))
3125  break;
3126  /* FIXME: allow user to disable IPv6 per configuration option... */
3127  got_ip = GNUNET_YES;
3128  in = (struct sockaddr_in6 *) &s5r->destination_address;
3129  in->sin6_family = AF_INET6;
3130  GNUNET_memcpy (&in->sin6_addr,
3131  r->data,
3132  r->data_size);
3133  in->sin6_port = htons (s5r->port);
3134 #if HAVE_SOCKADDR_IN_SIN_LEN
3135  in->sin6_len = sizeof(*in);
3136 #endif
3137  }
3138  break;
3139 
3141  GNUNET_break (0); /* should have been translated within GNS */
3142  break;
3143 
3145  GNUNET_free (s5r->leho);
3146  s5r->leho = GNUNET_strndup (r->data,
3147  r->data_size);
3148  break;
3149 
3151  {
3152  const struct GNUNET_GNSRECORD_BoxRecord *box;
3153 
3154  if (r->data_size < sizeof(struct GNUNET_GNSRECORD_BoxRecord))
3155  {
3156  GNUNET_break_op (0);
3157  break;
3158  }
3159  box = r->data;
3160  if ((ntohl (box->record_type) != GNUNET_DNSPARSER_TYPE_TLSA) ||
3161  (ntohs (box->protocol) != IPPROTO_TCP) ||
3162  (ntohs (box->service) != s5r->port))
3163  break; /* BOX record does not apply */
3164  if (s5r->num_danes >= MAX_DANES)
3165  {
3166  GNUNET_break (0); /* MAX_DANES too small */
3167  break;
3168  }
3169  s5r->is_tls = GNUNET_YES; /* This should be TLS */
3170  s5r->dane_data_len[s5r->num_danes]
3171  = r->data_size - sizeof(struct GNUNET_GNSRECORD_BoxRecord);
3172  s5r->dane_data[s5r->num_danes]
3173  = GNUNET_memdup (&box[1],
3174  s5r->dane_data_len[s5r->num_danes]);
3175  s5r->num_danes++;
3176  break;
3177  }
3178 
3179  default:
3180  /* don't care */
3181  break;
3182  }
3183  }
3184  if ((GNUNET_YES != got_ip) &&
3185  (GNUNET_YES == tld))
3186  {
3188  "Name resolution failed to yield useful IP address.\n");
3189  signal_socks_failure (s5r,
3191  return;
3192  }
3193  s5r->state = SOCKS5_DATA_TRANSFER;
3194  signal_socks_success (s5r);
3195 }
#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.
static unsigned int rd_count
Number of records for currently parsed set.
static struct GNUNET_GNSRECORD_Data rd[50]
The record data under a single label.
#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, rd, rd_count, 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 3205 of file gnunet-gns-proxy.c.

3207 {
3208  GNUNET_assert (len <= s5r->rbuf_len);
3209  memmove (s5r->rbuf,
3210  &s5r->rbuf[len],
3211  s5r->rbuf_len - len);
3212  s5r->rbuf_len -= len;
3213 }
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 3222 of file gnunet-gns-proxy.c.

3223 {
3224  struct Socks5Request *s5r = cls;
3225  const struct Socks5ClientHelloMessage *c_hello;
3226  struct Socks5ServerHelloMessage *s_hello;
3227  const struct Socks5ClientRequestMessage *c_req;
3228  ssize_t rlen;
3229  size_t alen;
3230  const struct GNUNET_SCHEDULER_TaskContext *tc;
3231 
3232  s5r->rtask = NULL;
3234  if ((NULL != tc->read_ready) &&
3236  s5r->sock)))
3237  {
3238  rlen = GNUNET_NETWORK_socket_recv (s5r->sock,
3239  &s5r->rbuf[s5r->rbuf_len],
3240  sizeof(s5r->rbuf) - s5r->rbuf_len);
3241  if (rlen <= 0)
3242  {
3244  "socks5 client disconnected.\n");
3245  cleanup_s5r (s5r);
3246  return;
3247  }
3248  s5r->rbuf_len += rlen;
3249  }
3251  s5r->sock,
3252  &do_s5r_read, s5r);
3254  "Processing %zu bytes of socks data in state %d\n",
3255  s5r->rbuf_len,
3256  s5r->state);
3257  switch (s5r->state)
3258  {
3259  case SOCKS5_INIT:
3260  c_hello = (const struct Socks5ClientHelloMessage*) &s5r->rbuf;
3261  if ((s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)) ||
3262  (s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)
3263  + c_hello->num_auth_methods))
3264  return; /* need more data */
3265  if (SOCKS_VERSION_5 != c_hello->version)
3266  {
3268  _ ("Unsupported socks version %d\n"),
3269  (int) c_hello->version);
3270  cleanup_s5r (s5r);
3271  return;
3272  }
3273  clear_from_s5r_rbuf (s5r,
3274  sizeof(struct Socks5ClientHelloMessage)
3275  + c_hello->num_auth_methods);
3276  GNUNET_assert (0 == s5r->wbuf_len);
3277  s_hello = (struct Socks5ServerHelloMessage *) &s5r->wbuf;
3278  s5r->wbuf_len = sizeof(struct Socks5ServerHelloMessage);
3279  s_hello->version = SOCKS_VERSION_5;
3280  s_hello->auth_method = SOCKS_AUTH_NONE;
3281  GNUNET_assert (NULL == s5r->wtask);
3283  s5r->sock,
3284  &do_write, s5r);
3285  s5r->state = SOCKS5_REQUEST;
3286  return;
3287 
3288  case SOCKS5_REQUEST:
3289  c_req = (const struct Socks5ClientRequestMessage *) &s5r->rbuf;
3290  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage))
3291  return;
3292  switch (c_req->command)
3293  {
3294  case SOCKS5_CMD_TCP_STREAM:
3295  /* handled below */
3296  break;
3297 
3298  default:
3300  _ ("Unsupported socks command %d\n"),
3301  (int) c_req->command);
3302  signal_socks_failure (s5r,
3304  return;
3305  }
3306  switch (c_req->addr_type)
3307  {
3308  case SOCKS5_AT_IPV4:
3309  {
3310  const struct in_addr *v4 = (const struct in_addr *) &c_req[1];
3311  const uint16_t *port = (const uint16_t *) &v4[1];
3312  struct sockaddr_in *in;
3313 
3314  s5r->port = ntohs (*port);
3315  alen = sizeof(struct in_addr);
3316  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3317  + alen + sizeof(uint16_t))
3318  return; /* need more data */
3319  in = (struct sockaddr_in *) &s5r->destination_address;
3320  in->sin_family = AF_INET;
3321  in->sin_addr = *v4;
3322  in->sin_port = *port;
3323 #if HAVE_SOCKADDR_IN_SIN_LEN
3324  in->sin_len = sizeof(*in);
3325 #endif
3326  s5r->state = SOCKS5_DATA_TRANSFER;
3327  }
3328  break;
3329 
3330  case SOCKS5_AT_IPV6:
3331  {
3332  const struct in6_addr *v6 = (const struct in6_addr *) &c_req[1];
3333  const uint16_t *port = (const uint16_t *) &v6[1];
3334  struct sockaddr_in6 *in;
3335 
3336  s5r->port = ntohs (*port);
3337  alen = sizeof(struct in6_addr);
3338  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3339  + alen + sizeof(uint16_t))
3340  return; /* need more data */
3341  in = (struct sockaddr_in6 *) &s5r->destination_address;
3342  in->sin6_family = AF_INET6;
3343  in->sin6_addr = *v6;
3344  in->sin6_port = *port;
3345 #if HAVE_SOCKADDR_IN_SIN_LEN
3346  in->sin6_len = sizeof(*in);
3347 #endif
3348  s5r->state = SOCKS5_DATA_TRANSFER;
3349  }
3350  break;
3351 
3352  case SOCKS5_AT_DOMAINNAME:
3353  {
3354  const uint8_t *dom_len;
3355  const char *dom_name;
3356  const uint16_t *port;
3357 
3358  dom_len = (const uint8_t *) &c_req[1];
3359  alen = *dom_len + 1;
3360  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3361  + alen + sizeof(uint16_t))
3362  return; /* need more data */
3363  dom_name = (const char *) &dom_len[1];
3364  port = (const uint16_t *) &dom_name[*dom_len];
3365  s5r->domain = GNUNET_strndup (dom_name,
3366  *dom_len);
3368  "Requested connection is to %s:%d\n",
3369  // (HTTPS_PORT == s5r->port) ? "s" : "",
3370  s5r->domain,
3371  ntohs (*port));
3372  s5r->state = SOCKS5_RESOLVING;
3373  s5r->port = ntohs (*port);
3374  s5r->is_tls = (HTTPS_PORT == s5r->port) ? GNUNET_YES : GNUNET_NO;
3376  s5r->domain,
3378  GNUNET_GNS_LO_LOCAL_MASTER /* only cached */,
3380  s5r);
3381  break;
3382  }
3383 
3384  default:
3386  _ ("Unsupported socks address type %d\n"),
3387  (int) c_req->addr_type);
3388  signal_socks_failure (s5r,
3390  return;
3391  }
3392  clear_from_s5r_rbuf (s5r,
3393  sizeof(struct Socks5ClientRequestMessage)
3394  + alen + sizeof(uint16_t));
3395  if (0 != s5r->rbuf_len)
3396  {
3397  /* read more bytes than healthy, why did the client send more!? */
3398  GNUNET_break_op (0);
3399  signal_socks_failure (s5r,
3401  return;
3402  }
3403  if (SOCKS5_DATA_TRANSFER == s5r->state)
3404  {
3405  /* if we are not waiting for GNS resolution, signal success */
3406  signal_socks_success (s5r);
3407  }
3408  /* We are done reading right now */
3410  s5r->rtask = NULL;
3411  return;
3412 
3413  case SOCKS5_RESOLVING:
3414  GNUNET_assert (0);
3415  return;
3416 
3417  case SOCKS5_DATA_TRANSFER:
3418  GNUNET_assert (0);
3419  return;
3420 
3421  default:
3422  GNUNET_assert (0);
3423  return;
3424  }
3425 }
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:716
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:949
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:1506
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:752
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:431
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

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:832
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:651
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:562
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:1334

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:70
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:400
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:1222
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().