GNUnet 0.21.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_identity_service.h"
#include "gns.h"
#include "gnunet_mhd_compat.h"
Include dependency graph for gnunet-gns-proxy.c:

Go to the source code of this file.

Data Structures

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

Macros

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

Enumerations

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

Functions

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

Variables

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

Macro Definition Documentation

◆ GNUNET_GNS_PROXY_PORT

#define GNUNET_GNS_PROXY_PORT   7777

Default Socks5 listen port.

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

◆ MAX_HTTP_URI_LENGTH

#define MAX_HTTP_URI_LENGTH   2048

Maximum supported length for a URI.

Should die.

Deprecated:

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

◆ MAX_DANES

#define MAX_DANES   32

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

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

◆ IO_BUFFERSIZE

#define IO_BUFFERSIZE   CURL_MAX_WRITE_SIZE

Size of the buffer for the data upload / download.

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

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

◆ SOCKS_BUFFERSIZE

#define SOCKS_BUFFERSIZE   (256 + 32)

Size of the read/write buffers for Socks.

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

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

◆ HTTP_PORT

#define HTTP_PORT   80

Port for plaintext HTTP.

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

◆ HTTPS_PORT

#define HTTPS_PORT   443

Port for HTTPS.

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

◆ MAX_PEM_SIZE

#define MAX_PEM_SIZE   (10 * 1024)

Largest allowed size for a PEM certificate.

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

◆ MHD_CACHE_TIMEOUT

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

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

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

◆ HTTP_HANDSHAKE_TIMEOUT

#define HTTP_HANDSHAKE_TIMEOUT
Value:
#define GNUNET_TIME_UNIT_SECONDS
One second.

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

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

◆ LOG_CURL_EASY

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

Log curl error.

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

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

◆ SOCKS_VERSION_5

#define SOCKS_VERSION_5   0x05

Which SOCKS version do we speak?

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

◆ SOCKS_AUTH_NONE

#define SOCKS_AUTH_NONE   0

Flag to set for 'no authentication'.

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

Enumeration Type Documentation

◆ Socks5Commands

Commands in Socks5.

Enumerator
SOCKS5_CMD_TCP_STREAM 

Establish TCP/IP stream.

SOCKS5_CMD_TCP_PORT 

Establish TCP port binding.

SOCKS5_CMD_UDP_PORT 

Establish UDP port binding.

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

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

◆ Socks5AddressType

Address types in Socks5.

Enumerator
SOCKS5_AT_IPV4 

IPv4 address.

SOCKS5_AT_DOMAINNAME 

IPv4 address.

SOCKS5_AT_IPV6 

IPv6 address.

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

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

◆ Socks5StatusCode

Status codes in Socks5 response.

Enumerator
SOCKS5_STATUS_REQUEST_GRANTED 
SOCKS5_STATUS_GENERAL_FAILURE 
SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE 
SOCKS5_STATUS_NETWORK_UNREACHABLE 
SOCKS5_STATUS_HOST_UNREACHABLE 
SOCKS5_STATUS_CONNECTION_REFUSED_BY_HOST 
SOCKS5_STATUS_TTL_EXPIRED 
SOCKS5_STATUS_COMMAND_NOT_SUPPORTED 
SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED 

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

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

◆ SocksPhase

enum SocksPhase

The socks phases.

Enumerator
SOCKS5_INIT 

We're waiting to get the client hello.

SOCKS5_REQUEST 

We're waiting to get the initial request.

SOCKS5_RESOLVING 

We are currently resolving the destination.

SOCKS5_DATA_TRANSFER 

We're in transfer mode.

SOCKS5_WRITE_THEN_CLEANUP 

Finish writing the write buffer, then clean up.

SOCKS5_SOCKET_WITH_MHD 

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

SOCKS5_SOCKET_UPLOAD_STARTED 

We've started receiving upload data from MHD.

SOCKS5_SOCKET_UPLOAD_DONE 

We've finished receiving upload data from MHD.

SOCKS5_SOCKET_DOWNLOAD_STARTED 

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

SOCKS5_SOCKET_DOWNLOAD_DONE 

We've finished receiving download data from cURL.

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

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

Function Documentation

◆ run_mhd_now()

static void run_mhd_now ( struct MhdHttpList hd)
static

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

Parameters
hdthe daemon to run now.

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

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

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

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

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

◆ cleanup_s5r()

static void cleanup_s5r ( struct Socks5Request s5r)
static

Clean up s5r handles.

Parameters
s5rthe handle to destroy

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

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

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

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

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

◆ curl_download_prepare()

static void curl_download_prepare ( )
static

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

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

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

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

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

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

◆ mhd_content_cb()

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

Callback for MHD response generation.

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

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

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

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

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

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

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

Referenced by create_response().

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

◆ create_mhd_response_from_s5r()

static int create_mhd_response_from_s5r ( struct Socks5Request s5r)
static

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

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

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

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

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

Referenced by curl_download_cb(), and curl_task_download().

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

◆ curl_download_cb()

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

Handle response payload data from cURL.

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

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

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

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

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

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

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

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

Referenced by curl_download_prepare().

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

◆ con_val_iter()

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

Read HTTP request header field from the request.

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

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

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

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

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

Referenced by create_response().

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

◆ create_response()

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

Main MHD callback for handling requests.

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

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

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

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

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

Referenced by lookup_ssl_httpd(), and run().

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

◆ mhd_completed_cb()

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

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

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

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

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

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

Referenced by lookup_ssl_httpd(), and run().

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

◆ mhd_connection_cb()

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

Function called when MHD connection is opened or closed.

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

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

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

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

Referenced by lookup_ssl_httpd(), and run().

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

◆ mhd_log_callback()

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

Function called when MHD first processes an incoming connection.

Gives us the respective URI information.

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

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

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

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

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

Referenced by lookup_ssl_httpd(), and run().

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

◆ kill_httpd()

static void kill_httpd ( struct MhdHttpList hd)
static

Kill the given MHD daemon.

Parameters
hddaemon to stop

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

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

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

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

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

◆ kill_httpd_task()

static void kill_httpd_task ( void *  cls)
static

Task run whenever HTTP server is idle for too long.

Kill it.

Parameters
clsthe struct MhdHttpList *

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

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

References MhdHttpList::httpd_task, and kill_httpd().

Referenced by schedule_httpd().

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

◆ do_httpd()

static void do_httpd ( void *  cls)
static

Task run whenever HTTP server operations are pending.

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

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

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

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

Referenced by run_mhd_now(), and schedule_httpd().

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

◆ schedule_httpd()

static void schedule_httpd ( struct MhdHttpList hd)
static

Schedule MHD.

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

Parameters
hdthe daemon to schedule

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

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

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

Referenced by do_httpd(), and setup_data_transfer().

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

◆ load_file()

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

Read file in filename.

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

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

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

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

Referenced by load_cert_from_file(), and load_key_from_file().

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

◆ load_key_from_file()

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

Load PEM key from file.

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

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

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

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

Referenced by run().

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

◆ load_cert_from_file()

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

Load cert from file.

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

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

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

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

Referenced by run().

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

◆ generate_gns_certificate()

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

Generate new certificate for specific name.

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

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

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

2786{
2787 /* do nothing */
2788}

Referenced by lookup_ssl_httpd().

Here is the caller graph for this function:

◆ lookup_ssl_httpd()

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

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

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

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

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

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

References cleanup_s5r(), and Socks5Request::timeout_task.

Referenced by setup_data_transfer().

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

◆ setup_data_transfer()

static void setup_data_transfer ( struct Socks5Request s5r)
static

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

Parameters
s5rsocks request that has reached the final stage

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

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

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

Referenced by do_write().

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

◆ do_write()

static void do_write ( void *  cls)
static

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

Parameters
clsthe closure with the struct Socks5Request

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

2943{
2944 struct Socks5Request *s5r = cls;
2945 ssize_t len;
2946
2947 s5r->wtask = NULL;
2948 len = GNUNET_NETWORK_socket_send (s5r->sock,
2949 s5r->wbuf,
2950 s5r->wbuf_len);
2951 if (len <= 0)
2952 {
2953 /* write error: connection closed, shutdown, etc.; just clean up */
2955 "Write Error\n");
2956 cleanup_s5r (s5r);
2957 return;
2958 }
2959 memmove (s5r->wbuf,
2960 &s5r->wbuf[len],
2961 s5r->wbuf_len - len);
2962 s5r->wbuf_len -= len;
2963 if (s5r->wbuf_len > 0)
2964 {
2965 /* not done writing */
2966 s5r->wtask =
2968 s5r->sock,
2969 &do_write, s5r);
2970 return;
2971 }
2972
2973 /* we're done writing, continue with state machine! */
2974
2975 switch (s5r->state)
2976 {
2977 case SOCKS5_INIT:
2978 GNUNET_assert (0);
2979 break;
2980
2981 case SOCKS5_REQUEST:
2982 GNUNET_assert (NULL != s5r->rtask);
2983 break;
2984
2986 setup_data_transfer (s5r);
2987 return;
2988
2990 cleanup_s5r (s5r);
2991 return;
2992
2993 default:
2994 GNUNET_break (0);
2995 break;
2996 }
2997}
static void do_write(void *cls)
Write data from buffer to socks5 client, then continue with state machine.
static void setup_data_transfer(struct Socks5Request *s5r)
We're done with the Socks5 protocol, now we need to pass the connection data through to the final des...
ssize_t GNUNET_NETWORK_socket_send(const struct GNUNET_NETWORK_Handle *desc, const void *buffer, size_t length)
Send data (always non-blocking).
Definition: network.c:737
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_write_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *wfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1583
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 3007 of file gnunet-gns-proxy.c.

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

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

Referenced by do_s5r_read(), and handle_gns_result().

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

◆ signal_socks_success()

static void signal_socks_success ( struct Socks5Request s5r)
static

Return a server response message indicating success.

Parameters
s5rrequest to return success status message for

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

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

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

Referenced by do_s5r_read(), and handle_gns_result().

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

◆ handle_gns_result()

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

Process GNS results for target domain.

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

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

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

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

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

Referenced by do_s5r_read().

Here is the caller graph for this function:

◆ do_s5r_read()

static void do_s5r_read ( void *  cls)
static

Read data from incoming Socks5 connection.

Parameters
clsthe closure with the struct Socks5Request

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

3223{
3224 struct Socks5Request *s5r = cls;
3225 const struct Socks5ClientHelloMessage *c_hello;
3226 struct Socks5ServerHelloMessage *s_hello;
3227 const struct Socks5ClientRequestMessage *c_req;
3228 ssize_t rlen;
3229 size_t alen;
3230 const struct GNUNET_SCHEDULER_TaskContext *tc;
3231
3232 s5r->rtask = NULL;
3234 if ((NULL != tc->read_ready) &&
3236 s5r->sock)))
3237 {
3238 rlen = GNUNET_NETWORK_socket_recv (s5r->sock,
3239 &s5r->rbuf[s5r->rbuf_len],
3240 sizeof(s5r->rbuf) - s5r->rbuf_len);
3241 if (rlen <= 0)
3242 {
3244 "socks5 client disconnected.\n");
3245 cleanup_s5r (s5r);
3246 return;
3247 }
3248 s5r->rbuf_len += rlen;
3249 }
3251 s5r->sock,
3252 &do_s5r_read, s5r);
3254 "Processing %zu bytes of socks data in state %d\n",
3255 s5r->rbuf_len,
3256 s5r->state);
3257 switch (s5r->state)
3258 {
3259 case SOCKS5_INIT:
3260 c_hello = (const struct Socks5ClientHelloMessage*) &s5r->rbuf;
3261 if ((s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)) ||
3262 (s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)
3263 + c_hello->num_auth_methods))
3264 return; /* need more data */
3265 if (SOCKS_VERSION_5 != c_hello->version)
3266 {
3268 _ ("Unsupported socks version %d\n"),
3269 (int) c_hello->version);
3270 cleanup_s5r (s5r);
3271 return;
3272 }
3274 sizeof(struct Socks5ClientHelloMessage)
3275 + c_hello->num_auth_methods);
3276 GNUNET_assert (0 == s5r->wbuf_len);
3277 s_hello = (struct Socks5ServerHelloMessage *) &s5r->wbuf;
3278 s5r->wbuf_len = sizeof(struct Socks5ServerHelloMessage);
3279 s_hello->version = SOCKS_VERSION_5;
3280 s_hello->auth_method = SOCKS_AUTH_NONE;
3281 GNUNET_assert (NULL == s5r->wtask);
3283 s5r->sock,
3284 &do_write, s5r);
3285 s5r->state = SOCKS5_REQUEST;
3286 return;
3287
3288 case SOCKS5_REQUEST:
3289 c_req = (const struct Socks5ClientRequestMessage *) &s5r->rbuf;
3290 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage))
3291 return;
3292 switch (c_req->command)
3293 {
3295 /* handled below */
3296 break;
3297
3298 default:
3300 _ ("Unsupported socks command %d\n"),
3301 (int) c_req->command);
3304 return;
3305 }
3306 switch (c_req->addr_type)
3307 {
3308 case SOCKS5_AT_IPV4:
3309 {
3310 const struct in_addr *v4 = (const struct in_addr *) &c_req[1];
3311 const uint16_t *port = (const uint16_t *) &v4[1];
3312 struct sockaddr_in *in;
3313
3314 s5r->port = ntohs (*port);
3315 alen = sizeof(struct in_addr);
3316 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3317 + alen + sizeof(uint16_t))
3318 return; /* need more data */
3319 in = (struct sockaddr_in *) &s5r->destination_address;
3320 in->sin_family = AF_INET;
3321 in->sin_addr = *v4;
3322 in->sin_port = *port;
3323#if HAVE_SOCKADDR_IN_SIN_LEN
3324 in->sin_len = sizeof(*in);
3325#endif
3327 }
3328 break;
3329
3330 case SOCKS5_AT_IPV6:
3331 {
3332 const struct in6_addr *v6 = (const struct in6_addr *) &c_req[1];
3333 const uint16_t *port = (const uint16_t *) &v6[1];
3334 struct sockaddr_in6 *in;
3335
3336 s5r->port = ntohs (*port);
3337 alen = sizeof(struct in6_addr);
3338 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3339 + alen + sizeof(uint16_t))
3340 return; /* need more data */
3341 in = (struct sockaddr_in6 *) &s5r->destination_address;
3342 in->sin6_family = AF_INET6;
3343 in->sin6_addr = *v6;
3344 in->sin6_port = *port;
3345#if HAVE_SOCKADDR_IN_SIN_LEN
3346 in->sin6_len = sizeof(*in);
3347#endif
3349 }
3350 break;
3351
3353 {
3354 const uint8_t *dom_len;
3355 const char *dom_name;
3356 const uint16_t *port;
3357
3358 dom_len = (const uint8_t *) &c_req[1];
3359 alen = *dom_len + 1;
3360 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3361 + alen + sizeof(uint16_t))
3362 return; /* need more data */
3363 dom_name = (const char *) &dom_len[1];
3364 port = (const uint16_t *) &dom_name[*dom_len];
3365 s5r->domain = GNUNET_strndup (dom_name,
3366 *dom_len);
3368 "Requested connection is to %s:%d\n",
3369 // (HTTPS_PORT == s5r->port) ? "s" : "",
3370 s5r->domain,
3371 ntohs (*port));
3372 s5r->state = SOCKS5_RESOLVING;
3373 s5r->port = ntohs (*port);
3374 s5r->is_tls = (HTTPS_PORT == s5r->port) ? GNUNET_YES : GNUNET_NO;
3376 s5r->domain,
3378 GNUNET_GNS_LO_LOCAL_MASTER /* only cached */,
3380 s5r);
3381 break;
3382 }
3383
3384 default:
3386 _ ("Unsupported socks address type %d\n"),
3387 (int) c_req->addr_type);
3390 return;
3391 }
3393 sizeof(struct Socks5ClientRequestMessage)
3394 + alen + sizeof(uint16_t));
3395 if (0 != s5r->rbuf_len)
3396 {
3397 /* read more bytes than healthy, why did the client send more!? */
3398 GNUNET_break_op (0);
3401 return;
3402 }
3403 if (SOCKS5_DATA_TRANSFER == s5r->state)
3404 {
3405 /* if we are not waiting for GNS resolution, signal success */
3407 }
3408 /* We are done reading right now */
3410 s5r->rtask = NULL;
3411 return;
3412
3413 case SOCKS5_RESOLVING:
3414 GNUNET_assert (0);
3415 return;
3416
3418 GNUNET_assert (0);
3419 return;
3420
3421 default:
3422 GNUNET_assert (0);
3423 return;
3424 }
3425}
static void do_s5r_read(void *cls)
Read data from incoming Socks5 connection.
static struct GNUNET_GNS_Handle * gns_handle
Handle to the GNS service.
#define SOCKS_AUTH_NONE
Flag to set for 'no authentication'.
static void clear_from_s5r_rbuf(struct Socks5Request *s5r, size_t len)
Remove the first len bytes from the beginning of the read buffer.
#define HTTPS_PORT
Port for HTTPS.
static void handle_gns_result(void *cls, int tld, uint32_t rd_count, const struct GNUNET_GNSRECORD_Data *rd)
Process GNS results for target domain.
struct GNUNET_GNS_LookupWithTldRequest * GNUNET_GNS_lookup_with_tld(struct GNUNET_GNS_Handle *handle, const char *name, uint32_t type, enum GNUNET_GNS_LocalOptions options, GNUNET_GNS_LookupResultProcessor2 proc, void *proc_cls)
Perform an asynchronous lookup operation on the GNS, determining the zone using the TLD of the given ...
Definition: gns_tld_api.c: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:716
int GNUNET_NETWORK_fdset_isset(const struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_NETWORK_Handle *desc)
Check whether a socket is part of the fd set.
Definition: network.c:949
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1512
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:758
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:431
Context information passed to each scheduler task.
const struct GNUNET_NETWORK_FDSet * read_ready
Set of file descriptors ready for reading; note that additional bits may be set that were not in the ...
Client hello in Socks5 protocol.
uint8_t version
Should be SOCKS_VERSION_5.
uint8_t num_auth_methods
How many authentication methods does the client support.
Client socks request in Socks5 protocol.
uint8_t command
Command code, we only uspport SOCKS5_CMD_TCP_STREAM.
uint8_t addr_type
Address type, an enum Socks5AddressType.
Server hello in Socks5 protocol.
uint8_t version
Should be SOCKS_VERSION_5.
uint8_t auth_method
Chosen authentication method, for us always SOCKS_AUTH_NONE, which skips the authentication step.

References _, Socks5ClientRequestMessage::addr_type, Socks5ServerHelloMessage::auth_method, cleanup_s5r(), clear_from_s5r_rbuf(), Socks5ClientRequestMessage::command, Socks5Request::destination_address, do_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, 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 3434 of file gnunet-gns-proxy.c.

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

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

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

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

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

Referenced by run().

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

◆ bind_v6()

static struct GNUNET_NETWORK_Handle * bind_v6 ( )
static

Create an IPv6 listen socket bound to our port.

Returns
NULL on error

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

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

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

Referenced by run().

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

◆ run()

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

Main function that will be run.

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

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

3635{
3636 char*cafile_cfg = NULL;
3637 char*cafile;
3638 char*addr_str;
3639 struct MhdHttpList *hd;
3640
3641 cfg = c;
3642
3643 /* Get address to bind to */
3645 "BIND_TO",
3646 &addr_str))
3647 {
3648 // No address specified
3650 "Don't know what to bind to...\n");
3651 GNUNET_free (addr_str);
3653 return;
3654 }
3655 if (1 != inet_pton (AF_INET, addr_str, &address))
3656 {
3658 "Unable to parse address %s\n",
3659 addr_str);
3660 GNUNET_free (addr_str);
3662 return;
3663 }
3664 GNUNET_free (addr_str);
3665 /* Get address to bind to */
3667 "BIND_TO6",
3668 &addr_str))
3669 {
3670 // No address specified
3672 "Don't know what to bind6 to...\n");
3673 GNUNET_free (addr_str);
3675 return;
3676 }
3677 if (1 != inet_pton (AF_INET6, addr_str, &address6))
3678 {
3680 "Unable to parse IPv6 address %s\n",
3681 addr_str);
3682 GNUNET_free (addr_str);
3684 return;
3685 }
3686 GNUNET_free (addr_str);
3687
3688 if (NULL == (curl_multi = curl_multi_init ()))
3689 {
3691 "Failed to create cURL multi handle!\n");
3692 return;
3693 }
3694 cafile = cafile_opt;
3695 if (NULL == cafile)
3696 {
3697 if (GNUNET_OK !=
3699 "gns-proxy",
3700 "PROXY_CACERT",
3701 &cafile_cfg))
3702 {
3704 "gns-proxy",
3705 "PROXY_CACERT");
3706 return;
3707 }
3708 cafile = cafile_cfg;
3709 }
3711 "Using `%s' as CA\n",
3712 cafile);
3713
3714 gnutls_global_init ();
3715 gnutls_x509_crt_init (&proxy_ca.cert);
3716 gnutls_x509_privkey_init (&proxy_ca.key);
3717
3718 if ((GNUNET_OK !=
3720 cafile)) ||
3721 (GNUNET_OK !=
3723 cafile)))
3724 {
3726 _ ("Failed to load X.509 key and certificate from `%s'\n"),
3727 cafile);
3728 gnutls_x509_crt_deinit (proxy_ca.cert);
3729 gnutls_x509_privkey_deinit (proxy_ca.key);
3730 gnutls_global_deinit ();
3731 GNUNET_free (cafile_cfg);
3732 return;
3733 }
3734 GNUNET_free (cafile_cfg);
3735 if (NULL == (gns_handle = GNUNET_GNS_connect (cfg)))
3736 {
3738 "Unable to connect to GNS!\n");
3739 gnutls_x509_crt_deinit (proxy_ca.cert);
3740 gnutls_x509_privkey_deinit (proxy_ca.key);
3741 gnutls_global_deinit ();
3742 return;
3743 }
3745 NULL);
3746
3747 /* Open listen socket for socks proxy */
3748 lsock6 = bind_v6 ();
3749 if (NULL == lsock6)
3750 {
3752 "bind");
3753 }
3754 else
3755 {
3756 if (GNUNET_OK !=
3758 5))
3759 {
3761 "listen");
3763 lsock6 = NULL;
3764 }
3765 else
3766 {
3768 lsock6,
3769 &do_accept,
3770 lsock6);
3771 }
3772 }
3773 lsock4 = bind_v4 ();
3774 if (NULL == lsock4)
3775 {
3777 "bind");
3778 }
3779 else
3780 {
3781 if (GNUNET_OK !=
3783 5))
3784 {
3786 "listen");
3788 lsock4 = NULL;
3789 }
3790 else
3791 {
3793 lsock4,
3794 &do_accept,
3795 lsock4);
3796 }
3797 }
3798 if ((NULL == lsock4) &&
3799 (NULL == lsock6))
3800 {
3802 return;
3803 }
3804 if (CURLSSLSET_OK != curl_global_sslset (CURLSSLBACKEND_GNUTLS,
3805 NULL,
3806 NULL))
3807 {
3809 "cURL does not support the GnuTLS backend\n");
3810
3811 }
3812 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
3813 {
3815 "cURL global init failed!\n");
3817 return;
3818 }
3820 "Proxy listens on port %u\n",
3821 (unsigned int) port);
3822
3823 /* start MHD daemon for HTTP */
3824 hd = GNUNET_new (struct MhdHttpList);
3825 hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
3826 | MHD_ALLOW_SUSPEND_RESUME,
3827 0,
3828 NULL, NULL,
3829 &create_response, hd,
3830 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
3831 int) 16,
3832 MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
3833 NULL,
3834 MHD_OPTION_NOTIFY_CONNECTION,
3835 &mhd_connection_cb, NULL,
3836 MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
3837 NULL,
3838 MHD_OPTION_END);
3839 if (NULL == hd->daemon)
3840 {
3841 GNUNET_free (hd);
3843 return;
3844 }
3845 httpd = hd;
3848 hd);
3849}
static struct GNUNET_NETWORK_Handle * bind_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:651
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:567
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:1340

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

Referenced by main().

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

◆ main()

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

The main function for gnunet-gns-proxy.

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

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

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

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

Here is the call graph for this function:

Variable Documentation

◆ address

in_addr_t address
static

The address to bind to.

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

Referenced by bind_v4(), and run().

◆ address6

struct in6_addr address6
static

The IPv6 address to bind to.

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

Referenced by bind_v6(), and run().

◆ port

uint16_t port = 7777
static

The port the proxy is running on (default 7777)

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

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

◆ cafile_opt

char* cafile_opt
static

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

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

Referenced by main(), and run().

◆ lsock4

struct GNUNET_NETWORK_Handle* lsock4
static

The listen socket of the proxy for IPv4.

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

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

◆ lsock6

struct GNUNET_NETWORK_Handle* lsock6
static

The listen socket of the proxy for IPv6.

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

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

◆ ltask4

struct GNUNET_SCHEDULER_Task* ltask4
static

The listen task ID for IPv4.

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

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

◆ ltask6

struct GNUNET_SCHEDULER_Task* ltask6
static

The listen task ID for IPv6.

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

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

◆ curl_download_task

struct GNUNET_SCHEDULER_Task* curl_download_task
static

The cURL download task (curl multi API).

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

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

◆ curl_multi

CURLM* curl_multi
static

◆ gns_handle

struct GNUNET_GNS_Handle* gns_handle
static

Handle to the GNS service.

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

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

◆ disable_v6

int disable_v6
static

Disable IPv6.

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

Referenced by handle_gns_result(), and main().

◆ mhd_httpd_head

struct MhdHttpList* mhd_httpd_head
static

DLL for http/https daemons.

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

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

◆ mhd_httpd_tail

struct MhdHttpList* mhd_httpd_tail
static

DLL for http/https daemons.

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

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

◆ httpd

struct MhdHttpList* httpd
static

Daemon for HTTP (we have one per X.509 certificate, and then one for all HTTP connections; this is the one for HTTP, not HTTPS).

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

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

◆ s5r_head

struct Socks5Request* s5r_head
static

DLL of active socks requests.

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

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

◆ s5r_tail

struct Socks5Request* s5r_tail
static

DLL of active socks requests.

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

Referenced by cleanup_s5r(), and do_accept().

◆ proxy_ca

struct ProxyCA proxy_ca
static

The CA for X.509 certificate generation.

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

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

◆ curl_failure_response

struct MHD_Response* curl_failure_response
static

Response we return on cURL failures.

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

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

◆ cfg

const struct GNUNET_CONFIGURATION_Handle* cfg
static

Our configuration.

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

Referenced by run().