GNUnet 0.22.1
gnunet-gns-proxy.c File Reference
#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_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 (void)
 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...
 

Macro Definition Documentation

◆ GNUNET_GNS_PROXY_PORT

#define GNUNET_GNS_PROXY_PORT   7777

Default Socks5 listen port.

Definition at line 49 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 55 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 61 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 67 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 74 of file gnunet-gns-proxy.c.

◆ HTTP_PORT

#define HTTP_PORT   80

Port for plaintext HTTP.

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

◆ HTTPS_PORT

#define HTTPS_PORT   443

Port for HTTPS.

Definition at line 84 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 89 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:486

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

Definition at line 94 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 101 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 112 of file gnunet-gns-proxy.c.

◆ SOCKS_VERSION_5

#define SOCKS_VERSION_5   0x05

Which SOCKS version do we speak?

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

◆ SOCKS_AUTH_NONE

#define SOCKS_AUTH_NONE   0

Flag to set for 'no authentication'.

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

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

160{
164 SOCKS5_AT_IPV4 = 1,
165
170
175};
@ 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 181 of file gnunet-gns-proxy.c.

182{
192};
@ 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 382 of file gnunet-gns-proxy.c.

383{
388
393
398
403
408
413
418
423
428
433};
@ 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 2584 of file gnunet-gns-proxy.c.

2585{
2586 if (NULL != hd->httpd_task)
2589 hd);
2590}
static void do_httpd(void *cls)
Task run whenever HTTP server operations are pending.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:979
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:1303
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 772 of file gnunet-gns-proxy.c.

773{
775 "Cleaning up socks request\n");
776 if (NULL != s5r->curl)
777 {
779 "Cleaning up cURL handle\n");
780 curl_multi_remove_handle (curl_multi,
781 s5r->curl);
782 curl_easy_cleanup (s5r->curl);
783 s5r->curl = NULL;
784 }
785 if (s5r->suspended)
786 {
787 s5r->suspended = GNUNET_NO;
788 MHD_resume_connection (s5r->con);
789 }
790 curl_slist_free_all (s5r->headers);
791 if (NULL != s5r->hosts)
792 {
793 curl_slist_free_all (s5r->hosts);
794 }
795 if ((NULL != s5r->response) &&
797 {
798 MHD_destroy_response (s5r->response);
799 s5r->response = NULL;
800 }
801 if (NULL != s5r->rtask)
802 {
804 s5r->rtask = NULL;
805 }
806 if (NULL != s5r->timeout_task)
807 {
809 s5r->timeout_task = NULL;
810 }
811 if (NULL != s5r->wtask)
812 {
814 s5r->wtask = NULL;
815 }
816 if (NULL != s5r->gns_lookup)
817 {
819 s5r->gns_lookup = NULL;
820 }
821 if (NULL != s5r->sock)
822 {
823 if (SOCKS5_SOCKET_WITH_MHD <= s5r->state)
825 else
827 s5r->sock = NULL;
828 }
830 s5r_tail,
831 s5r);
832 GNUNET_free (s5r->domain);
833 GNUNET_free (s5r->leho);
834 GNUNET_free (s5r->url);
835 for (unsigned int i = 0; i < s5r->num_danes; i++)
836 GNUNET_free (s5r->dane_data[i]);
837 GNUNET_free (s5r);
838}
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:331
@ 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:566
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 ( void  )
static

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

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

1570{
1571 CURLMcode mret;
1572 fd_set rs;
1573 fd_set ws;
1574 fd_set es;
1575 int max;
1576 struct GNUNET_NETWORK_FDSet *grs;
1577 struct GNUNET_NETWORK_FDSet *gws;
1578 long to;
1579 struct GNUNET_TIME_Relative rtime;
1580
1582 "Scheduling CURL interaction\n");
1583 if (NULL != curl_download_task)
1584 {
1586 curl_download_task = NULL;
1587 }
1588 max = -1;
1589 FD_ZERO (&rs);
1590 FD_ZERO (&ws);
1591 FD_ZERO (&es);
1592 if (CURLM_OK != (mret = curl_multi_fdset (curl_multi,
1593 &rs,
1594 &ws,
1595 &es,
1596 &max)))
1597 {
1599 "%s failed at %s:%d: `%s'\n",
1600 "curl_multi_fdset", __FILE__, __LINE__,
1601 curl_multi_strerror (mret));
1602 return;
1603 }
1604 to = -1;
1605 GNUNET_break (CURLM_OK ==
1606 curl_multi_timeout (curl_multi,
1607 &to));
1608 if (-1 == to)
1610 else
1612 to);
1613 if (-1 != max)
1614 {
1618 &rs,
1619 max + 1);
1621 &ws,
1622 max + 1);
1625 rtime,
1626 grs,
1627 gws,
1629 curl_multi);
1632 }
1633 else
1634 {
1637 curl_multi);
1638 }
1639}
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
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1187
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:1041
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1171
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:1834
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:1276
#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 859 of file gnunet-gns-proxy.c.

863{
864 struct Socks5Request *s5r = cls;
865 size_t bytes_to_copy;
866
867 if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
869 {
870 /* we're still not done with the upload, do not yet
871 start the download, the IO buffer is still full
872 with upload data. */
874 "Pausing MHD download %s%s, not yet ready for download\n",
875 s5r->domain,
876 s5r->url);
877 return 0; /* not yet ready for data download */
878 }
879 bytes_to_copy = GNUNET_MIN (max,
880 s5r->io_len);
881 if ((0 == bytes_to_copy) &&
883 {
885 "Pausing MHD download %s%s, no data available\n",
886 s5r->domain,
887 s5r->url);
888 if (NULL != s5r->curl)
889 {
891 "Continuing CURL interaction for %s%s\n",
892 s5r->domain,
893 s5r->url);
894 if (GNUNET_YES == s5r->curl_paused)
895 {
896 s5r->curl_paused = GNUNET_NO;
897 curl_easy_pause (s5r->curl,
898 CURLPAUSE_CONT);
899 }
901 }
902 if (GNUNET_NO == s5r->suspended)
903 {
904 MHD_suspend_connection (s5r->con);
905 s5r->suspended = GNUNET_YES;
906 }
907 return 0; /* more data later */
908 }
909 if ((0 == bytes_to_copy) &&
911 {
913 "Completed MHD download %s%s\n",
914 s5r->domain,
915 s5r->url);
916 return MHD_CONTENT_READER_END_OF_STREAM;
917 }
919 "Writing %llu/%llu bytes to %s%s\n",
920 (unsigned long long) bytes_to_copy,
921 (unsigned long long) s5r->io_len,
922 s5r->domain,
923 s5r->url);
924 GNUNET_memcpy (buf,
925 s5r->io_buf,
926 bytes_to_copy);
927 memmove (s5r->io_buf,
928 &s5r->io_buf[bytes_to_copy],
929 s5r->io_len - bytes_to_copy);
930 s5r->io_len -= bytes_to_copy;
931 if ((NULL != s5r->curl) &&
932 (GNUNET_YES == s5r->curl_paused))
933 {
935 "Continuing CURL interaction for %s%s\n",
936 s5r->domain,
937 s5r->url);
938 s5r->curl_paused = GNUNET_NO;
939 curl_easy_pause (s5r->curl,
940 CURLPAUSE_CONT);
941 }
942 return bytes_to_copy;
943}
static void curl_download_prepare(void)
Ask cURL for the select() sets and schedule cURL operations.
#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 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 955 of file gnunet-gns-proxy.c.

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

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

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

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

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

References 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, 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 1648 of file gnunet-gns-proxy.c.

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

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

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

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

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

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

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

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

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

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

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

2603{
2604 void *buffer;
2605 uint64_t fsize;
2606
2607 if (GNUNET_OK !=
2609 &fsize,
2610 GNUNET_YES,
2611 GNUNET_YES))
2612 return NULL;
2613 if (fsize > MAX_PEM_SIZE)
2614 return NULL;
2615 *size = (unsigned int) fsize;
2616 buffer = GNUNET_malloc (*size);
2617 if (fsize !=
2619 buffer,
2620 (size_t) fsize))
2621 {
2622 GNUNET_free (buffer);
2623 return NULL;
2624 }
2625 return buffer;
2626}
static char * filename
#define MAX_PEM_SIZE
Largest allowed size for a PEM certificate.
enum GNUNET_GenericReturnValue GNUNET_DISK_file_size(const char *filename, uint64_t *size, int include_symbolic_links, int single_file_mode)
Get the size of the file (or directory) of the given file (in bytes).
Definition: disk.c:222
ssize_t GNUNET_DISK_fn_read(const char *fn, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:665

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

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

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

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

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

2784{
2785 /* do nothing */
2786}

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

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

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

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

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

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

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

References cleanup_s5r(), do_write(), GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_NETWORK_socket_send(), GNUNET_SCHEDULER_add_write_net(), GNUNET_TIME_UNIT_FOREVER_REL, 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(), do_write(), 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 3005 of file gnunet-gns-proxy.c.

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

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

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

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

References GNUNET_assert, 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 3220 of file gnunet-gns-proxy.c.

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

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

3433{
3434 struct GNUNET_NETWORK_Handle *lsock = cls;
3435 struct GNUNET_NETWORK_Handle *s;
3436 struct Socks5Request *s5r;
3437
3438 GNUNET_assert (NULL != lsock);
3439 if (lsock == lsock4)
3441 lsock,
3442 &do_accept,
3443 lsock);
3444 else if (lsock == lsock6)
3446 lsock,
3447 &do_accept,
3448 lsock);
3449 else
3450 GNUNET_assert (0);
3452 NULL,
3453 NULL);
3454 if (NULL == s)
3455 {
3457 "accept");
3458 return;
3459 }
3461 "Got an inbound connection, waiting for data\n");
3462 s5r = GNUNET_new (struct Socks5Request);
3464 s5r_tail,
3465 s5r);
3466 s5r->sock = s;
3467 s5r->state = SOCKS5_INIT;
3469 s5r->sock,
3470 &do_s5r_read,
3471 s5r);
3472}
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_accept(), 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 do_accept(), and 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 3484 of file gnunet-gns-proxy.c.

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

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

3551{
3552 struct GNUNET_NETWORK_Handle *ls;
3553 struct sockaddr_in sa4;
3554 int eno;
3555
3556 memset (&sa4, 0, sizeof(sa4));
3557 sa4.sin_family = AF_INET;
3558 sa4.sin_port = htons (port);
3559 sa4.sin_addr.s_addr = address;
3560#if HAVE_SOCKADDR_IN_SIN_LEN
3561 sa4.sin_len = sizeof(sa4);
3562#endif
3564 SOCK_STREAM,
3565 0);
3566 if (NULL == ls)
3567 return NULL;
3568 if (GNUNET_OK !=
3570 (const struct sockaddr *) &sa4,
3571 sizeof(sa4)))
3572 {
3573 eno = errno;
3575 errno = eno;
3576 return NULL;
3577 }
3578 return ls;
3579}
static uint16_t port
The port the proxy is running on (default 7777)
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:833
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().

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

3589{
3590 struct GNUNET_NETWORK_Handle *ls;
3591 struct sockaddr_in6 sa6;
3592 int eno;
3593
3594 memset (&sa6, 0, sizeof(sa6));
3595 sa6.sin6_family = AF_INET6;
3596 sa6.sin6_port = htons (port);
3597 sa6.sin6_addr = address6;
3598#if HAVE_SOCKADDR_IN_SIN_LEN
3599 sa6.sin6_len = sizeof(sa6);
3600#endif
3601 ls = GNUNET_NETWORK_socket_create (AF_INET6,
3602 SOCK_STREAM,
3603 0);
3604 if (NULL == ls)
3605 return NULL;
3606 if (GNUNET_OK !=
3608 (const struct sockaddr *) &sa6,
3609 sizeof(sa6)))
3610 {
3611 eno = errno;
3613 errno = eno;
3614 return NULL;
3615 }
3616 return ls;
3617}
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().

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

3633{
3634 char*cafile_cfg = NULL;
3635 char*cafile;
3636 char*addr_str;
3637 struct MhdHttpList *hd;
3638
3639 cfg = c;
3640
3641 /* Get address to bind to */
3643 "BIND_TO",
3644 &addr_str))
3645 {
3646 // No address specified
3648 "Don't know what to bind to...\n");
3649 GNUNET_free (addr_str);
3651 return;
3652 }
3653 if (1 != inet_pton (AF_INET, addr_str, &address))
3654 {
3656 "Unable to parse address %s\n",
3657 addr_str);
3658 GNUNET_free (addr_str);
3660 return;
3661 }
3662 GNUNET_free (addr_str);
3663 /* Get address to bind to */
3665 "BIND_TO6",
3666 &addr_str))
3667 {
3668 // No address specified
3670 "Don't know what to bind6 to...\n");
3671 GNUNET_free (addr_str);
3673 return;
3674 }
3675 if (1 != inet_pton (AF_INET6, addr_str, &address6))
3676 {
3678 "Unable to parse IPv6 address %s\n",
3679 addr_str);
3680 GNUNET_free (addr_str);
3682 return;
3683 }
3684 GNUNET_free (addr_str);
3685
3686 if (NULL == (curl_multi = curl_multi_init ()))
3687 {
3689 "Failed to create cURL multi handle!\n");
3690 return;
3691 }
3692 cafile = cafile_opt;
3693 if (NULL == cafile)
3694 {
3695 if (GNUNET_OK !=
3697 "gns-proxy",
3698 "PROXY_CACERT",
3699 &cafile_cfg))
3700 {
3702 "gns-proxy",
3703 "PROXY_CACERT");
3704 return;
3705 }
3706 cafile = cafile_cfg;
3707 }
3709 "Using `%s' as CA\n",
3710 cafile);
3711
3712 gnutls_global_init ();
3713 gnutls_x509_crt_init (&proxy_ca.cert);
3714 gnutls_x509_privkey_init (&proxy_ca.key);
3715
3716 if ((GNUNET_OK !=
3718 cafile)) ||
3719 (GNUNET_OK !=
3721 cafile)))
3722 {
3724 _ ("Failed to load X.509 key and certificate from `%s'\n"),
3725 cafile);
3726 gnutls_x509_crt_deinit (proxy_ca.cert);
3727 gnutls_x509_privkey_deinit (proxy_ca.key);
3728 gnutls_global_deinit ();
3729 GNUNET_free (cafile_cfg);
3730 return;
3731 }
3732 GNUNET_free (cafile_cfg);
3733 if (NULL == (gns_handle = GNUNET_GNS_connect (cfg)))
3734 {
3736 "Unable to connect to GNS!\n");
3737 gnutls_x509_crt_deinit (proxy_ca.cert);
3738 gnutls_x509_privkey_deinit (proxy_ca.key);
3739 gnutls_global_deinit ();
3740 return;
3741 }
3743 NULL);
3744
3745 /* Open listen socket for socks proxy */
3746 lsock6 = bind_v6 ();
3747 if (NULL == lsock6)
3748 {
3750 "bind");
3751 }
3752 else
3753 {
3754 if (GNUNET_OK !=
3756 5))
3757 {
3759 "listen");
3761 lsock6 = NULL;
3762 }
3763 else
3764 {
3766 lsock6,
3767 &do_accept,
3768 lsock6);
3769 }
3770 }
3771 lsock4 = bind_v4 ();
3772 if (NULL == lsock4)
3773 {
3775 "bind");
3776 }
3777 else
3778 {
3779 if (GNUNET_OK !=
3781 5))
3782 {
3784 "listen");
3786 lsock4 = NULL;
3787 }
3788 else
3789 {
3791 lsock4,
3792 &do_accept,
3793 lsock4);
3794 }
3795 }
3796 if ((NULL == lsock4) &&
3797 (NULL == lsock6))
3798 {
3800 return;
3801 }
3802 if (CURLSSLSET_OK != curl_global_sslset (CURLSSLBACKEND_GNUTLS,
3803 NULL,
3804 NULL))
3805 {
3807 "cURL does not support the GnuTLS backend\n");
3808
3809 }
3810 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
3811 {
3813 "cURL global init failed!\n");
3815 return;
3816 }
3818 "Proxy listens on port %u\n",
3819 (unsigned int) port);
3820
3821 /* start MHD daemon for HTTP */
3822 hd = GNUNET_new (struct MhdHttpList);
3823 hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
3824 | MHD_ALLOW_SUSPEND_RESUME,
3825 0,
3826 NULL, NULL,
3827 &create_response, hd,
3828 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
3829 int) 16,
3830 MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
3831 NULL,
3832 MHD_OPTION_NOTIFY_CONNECTION,
3833 &mhd_connection_cb, NULL,
3834 MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
3835 NULL,
3836 MHD_OPTION_END);
3837 if (NULL == hd->daemon)
3838 {
3839 GNUNET_free (hd);
3841 return;
3842 }
3843 httpd = hd;
3846 hd);
3847}
static struct GNUNET_NETWORK_Handle * bind_v4()
Create an IPv4 listen socket bound to our port.
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.
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:267
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:652
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:566
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:1338

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

3860{
3863 "port",
3864 NULL,
3865 gettext_noop (
3866 "listen on specified port (default: 7777)"),
3867 &port),
3869 "authority",
3870 NULL,
3871 gettext_noop ("pem file to use as CA"),
3872 &cafile_opt),
3874 "disable-ivp6",
3875 gettext_noop ("disable use of IPv6"),
3876 &disable_v6),
3877
3879 };
3880 static const char*page =
3881 "<html><head><title>gnunet-gns-proxy</title>"
3882 "</head><body>cURL fail</body></html>";
3883 int ret;
3884
3885 GNUNET_log_setup ("gnunet-gns-proxy",
3886 "WARNING",
3887 NULL);
3889 = MHD_create_response_from_buffer (strlen (page),
3890 (void *) page,
3891 MHD_RESPMEM_PERSISTENT);
3892
3893 ret =
3894 (GNUNET_OK ==
3895 GNUNET_PROGRAM_run (argc, argv,
3896 "gnunet-gns-proxy",
3897 _ ("GNUnet GNS proxy"),
3898 options,
3899 &run, NULL)) ? 0 : 1;
3900 MHD_destroy_response (curl_failure_response);
3901 return ret;
3902}
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:74
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.
enum GNUNET_GenericReturnValue GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
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
Definition of a command line option.

References _, cafile_opt, curl_failure_response, disable_v6, gettext_noop, GNUNET_GETOPT_OPTION_END, GNUNET_GETOPT_option_flag(), GNUNET_GETOPT_option_string(), GNUNET_GETOPT_option_uint16(), GNUNET_log_setup(), GNUNET_OK, GNUNET_PROGRAM_run(), 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 655 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 660 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 665 of file gnunet-gns-proxy.c.

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

◆ cafile_opt

char* cafile_opt
static

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

Definition at line 670 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 675 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 680 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 685 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 690 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 695 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 705 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 710 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 715 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 720 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 726 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 731 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 736 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 741 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 746 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 751 of file gnunet-gns-proxy.c.

Referenced by run().