GNUnet debian-0.24.3-29-g453fda2cf
 
Loading...
Searching...
No Matches
gnunet-gns-proxy.c File Reference
#include "platform.h"
#include <microhttpd.h>
#include "gnunet_curl_lib.h"
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/abstract.h>
#include <gnutls/crypto.h>
#include <regex.h>
#include "gnunet_util_lib.h"
#include "gnunet_gns_service.h"
#include "gnunet_mhd_compat.h"
Include dependency graph for gnunet-gns-proxy.c:

Go to the source code of this file.

Data Structures

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

Macros

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

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.
 
static void cleanup_s5r (struct Socks5Request *s5r)
 Clean up s5r handles.
 
static void curl_download_prepare (void)
 Ask cURL for the select() sets and schedule cURL operations.
 
static ssize_t mhd_content_cb (void *cls, uint64_t pos, char *buf, size_t max)
 Callback for MHD response generation.
 
static int check_ssl_certificate (struct Socks5Request *s5r)
 Check that the website has presented us with a valid X.509 certificate.
 
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 create_mhd_response_from_s5r (struct Socks5Request *s5r)
 Create an MHD response object in s5r matching the information we got from curl.
 
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_upload_cb (void *buf, size_t size, size_t nmemb, void *cls)
 cURL callback for uploaded (PUT/POST) data.
 
static void curl_task_download (void *cls)
 Task that is run when we are ready to receive more data 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 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_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 void * mhd_log_callback (void *cls, const char *url, struct MHD_Connection *connection)
 Function called when MHD first processes an incoming connection.
 
static void kill_httpd (struct MhdHttpList *hd)
 Kill the given MHD daemon.
 
static void kill_httpd_task (void *cls)
 Task run whenever HTTP server is idle for too long.
 
static void do_httpd (void *cls)
 Task run whenever HTTP server operations are pending.
 
static void schedule_httpd (struct MhdHttpList *hd)
 Schedule MHD.
 
static void * load_file (const char *filename, unsigned int *size)
 Read file in filename.
 
static int load_key_from_file (gnutls_x509_privkey_t key, const char *keyfile)
 Load PEM key from file.
 
static int load_cert_from_file (gnutls_x509_crt_t crt, const char *certfile)
 Load cert from file.
 
static struct ProxyGNSCertificategenerate_gns_certificate (const char *name)
 Generate new certificate for specific name.
 
static void mhd_error_log_callback (void *cls, const char *fm, va_list ap)
 Function called by MHD with errors, suppresses them all.
 
static struct MhdHttpListlookup_ssl_httpd (const char *domain)
 Lookup (or create) an TLS MHD instance for a particular domain.
 
static void timeout_s5r_handshake (void *cls)
 Task run when a Socks5Request somehow fails to be associated with an MHD connection (e.g.
 
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).
 
static void do_write (void *cls)
 Write data from buffer to socks5 client, then continue with state machine.
 
static void signal_socks_failure (struct Socks5Request *s5r, enum Socks5StatusCode sc)
 Return a server response message indicating a failure to the client.
 
static void signal_socks_success (struct Socks5Request *s5r)
 Return a server response message indicating success.
 
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.
 
static void clear_from_s5r_rbuf (struct Socks5Request *s5r, size_t len)
 Remove the first len bytes from the beginning of the read buffer.
 
static void do_s5r_read (void *cls)
 Read data from incoming Socks5 connection.
 
static void do_accept (void *cls)
 Accept new incoming connections.
 
static void do_shutdown (void *cls)
 Task run on shutdown.
 
static struct GNUNET_NETWORK_Handlebind_v4 ()
 Create an IPv4 listen socket bound to our port.
 
static struct GNUNET_NETWORK_Handlebind_v6 ()
 Create an IPv6 listen socket bound to our port.
 
static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
 Main function that will be run.
 
int main (int argc, char *const *argv)
 The main function for gnunet-gns-proxy.
 

Variables

static in_addr_t address
 The address to bind to.
 
static struct in6_addr address6
 The IPv6 address to bind to.
 
static uint16_t port = 7777
 The port the proxy is running on (default 7777)
 
static char * cafile_opt
 The CA file (pem) to use for the proxy CA.
 
static struct GNUNET_NETWORK_Handlelsock4
 The listen socket of the proxy for IPv4.
 
static struct GNUNET_NETWORK_Handlelsock6
 The listen socket of the proxy for IPv6.
 
static struct GNUNET_SCHEDULER_Taskltask4
 The listen task ID for IPv4.
 
static struct GNUNET_SCHEDULER_Taskltask6
 The listen task ID for IPv6.
 
static struct GNUNET_SCHEDULER_Taskcurl_download_task
 The cURL download task (curl multi API).
 
static CURLM * curl_multi
 The cURL multi handle.
 
static struct GNUNET_GNS_Handlegns_handle
 Handle to the GNS service.
 
static int disable_v6
 Disable IPv6.
 
static struct MhdHttpListmhd_httpd_head
 DLL for http/https daemons.
 
static struct MhdHttpListmhd_httpd_tail
 DLL for http/https daemons.
 
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).
 
static struct Socks5Requests5r_head
 DLL of active socks requests.
 
static struct Socks5Requests5r_tail
 DLL of active socks requests.
 
static struct ProxyCA proxy_ca
 The CA for X.509 certificate generation.
 
static struct MHD_Response * curl_failure_response
 Response we return on cURL failures.
 
static const struct GNUNET_CONFIGURATION_Handlecfg
 Our configuration.
 

Macro Definition Documentation

◆ GNUNET_GNS_PROXY_PORT

#define GNUNET_GNS_PROXY_PORT   7777

Default Socks5 listen port.

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

◆ MAX_HTTP_URI_LENGTH

#define MAX_HTTP_URI_LENGTH   2048

Maximum supported length for a URI.

Should die.

Deprecated:

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

◆ MAX_DANES

#define MAX_DANES   32

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

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

◆ IO_BUFFERSIZE

#define IO_BUFFERSIZE   CURL_MAX_WRITE_SIZE

Size of the buffer for the data upload / download.

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

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

◆ SOCKS_BUFFERSIZE

#define SOCKS_BUFFERSIZE   (256 + 32)

Size of the read/write buffers for Socks.

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

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

◆ HTTP_PORT

#define HTTP_PORT   80

Port for plaintext HTTP.

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

◆ HTTPS_PORT

#define HTTPS_PORT   443

Port for HTTPS.

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

◆ MAX_PEM_SIZE

#define MAX_PEM_SIZE   (10 * 1024)

Largest allowed size for a PEM certificate.

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

◆ MHD_CACHE_TIMEOUT

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

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

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

113 :%d: `%s'\n"), \
114 fun, \
115 __FILE__, \
116 __LINE__, \
117 curl_easy_strerror (rc))
118
119
120/* *************** Socks protocol definitions (move to TUN?) ****************** */
121
125#define SOCKS_VERSION_5 0x05
126
130#define SOCKS_AUTH_NONE 0
131
132
136enum Socks5Commands
137{
141 SOCKS5_CMD_TCP_STREAM = 1,
142
146 SOCKS5_CMD_TCP_PORT = 2,
147
151 SOCKS5_CMD_UDP_PORT = 3
152};
153
154
158enum Socks5AddressType
159{
163 SOCKS5_AT_IPV4 = 1,
164
168 SOCKS5_AT_DOMAINNAME = 3,
169
173 SOCKS5_AT_IPV6 = 4
174};
175
176
180enum Socks5StatusCode
181{
182 SOCKS5_STATUS_REQUEST_GRANTED = 0,
183 SOCKS5_STATUS_GENERAL_FAILURE = 1,
184 SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE = 2,
185 SOCKS5_STATUS_NETWORK_UNREACHABLE = 3,
186 SOCKS5_STATUS_HOST_UNREACHABLE = 4,
187 SOCKS5_STATUS_CONNECTION_REFUSED_BY_HOST = 5,
188 SOCKS5_STATUS_TTL_EXPIRED = 6,
189 SOCKS5_STATUS_COMMAND_NOT_SUPPORTED = 7,
190 SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED = 8
191};
192
193
197struct Socks5ClientHelloMessage
198{
202 uint8_t version;
203
207 uint8_t num_auth_methods;
208
209 /* followed by supported authentication methods, 1 byte per method */
210};
211
212
216struct Socks5ServerHelloMessage
217{
221 uint8_t version;
222
227 uint8_t auth_method;
228};
229
230
234struct Socks5ClientRequestMessage
235{
239 uint8_t version;
240
244 uint8_t command;
245
249 uint8_t resvd;
250
254 uint8_t addr_type;
255
256 /*
257 * Followed by either an ip4/ipv6 address or a domain name with a
258 * length field (uint8_t) in front (depending on @e addr_type).
259 * followed by port number in network byte order (uint16_t).
260 */
261};
262
263
267struct Socks5ServerResponseMessage
268{
272 uint8_t version;
273
277 uint8_t reply;
278
282 uint8_t reserved;
283
287 uint8_t addr_type;
288
289 /*
290 * Followed by either an ip4/ipv6 address or a domain name with a
291 * length field (uint8_t) in front (depending on @e addr_type).
292 * followed by port number in network byte order (uint16_t).
293 */
294};
295
296
297/* *********************** Datastructures for HTTP handling ****************** */
298
302struct ProxyCA
303{
307 gnutls_x509_crt_t cert;
308
312 gnutls_x509_privkey_t key;
313};
314
315
319struct ProxyGNSCertificate
320{
324 char cert[MAX_PEM_SIZE];
325
329 char key[MAX_PEM_SIZE];
330};
331
332
336struct MhdHttpList
337{
341 struct MhdHttpList *prev;
342
346 struct MhdHttpList *next;
347
351 char *domain;
352
356 struct MHD_Daemon *daemon;
357
361 struct ProxyGNSCertificate *proxy_cert;
362
366 struct GNUNET_SCHEDULER_Task *httpd_task;
367
371 int is_ssl;
372};
373
374
375/* ***************** Datastructures for Socks handling **************** */
376
377
381enum SocksPhase
382{
386 SOCKS5_INIT,
387
391 SOCKS5_REQUEST,
392
396 SOCKS5_RESOLVING,
397
401 SOCKS5_DATA_TRANSFER,
402
406 SOCKS5_WRITE_THEN_CLEANUP,
407
411 SOCKS5_SOCKET_WITH_MHD,
412
416 SOCKS5_SOCKET_UPLOAD_STARTED,
417
421 SOCKS5_SOCKET_UPLOAD_DONE,
422
426 SOCKS5_SOCKET_DOWNLOAD_STARTED,
427
431 SOCKS5_SOCKET_DOWNLOAD_DONE
432};
433
434
438struct HttpResponseHeader
439{
443 struct HttpResponseHeader *next;
444
448 struct HttpResponseHeader *prev;
449
453 char *type;
454
458 char *value;
459};
460
464struct Socks5Request
465{
469 struct Socks5Request *next;
470
474 struct Socks5Request *prev;
475
479 struct GNUNET_NETWORK_Handle *sock;
480
484 struct GNUNET_GNS_LookupWithTldRequest *gns_lookup;
485
489 struct GNUNET_SCHEDULER_Task *rtask;
490
494 struct GNUNET_SCHEDULER_Task *wtask;
495
499 struct GNUNET_SCHEDULER_Task *timeout_task;
500
504 char rbuf[SOCKS_BUFFERSIZE];
505
509 char wbuf[SOCKS_BUFFERSIZE];
510
514 char io_buf[IO_BUFFERSIZE];
515
519 struct MhdHttpList *hd;
520
524 struct MHD_Connection *con;
525
529 struct MHD_Response *response;
530
534 char *domain;
535
539 char *leho;
540
544 char *dane_data[MAX_DANES + 1];
545
549 char *url;
550
554 CURL *curl;
555
559 struct curl_slist *headers;
560
564 struct curl_slist *hosts;
565
569 unsigned int response_code;
570
574 int dane_data_len[MAX_DANES + 1];
575
580 unsigned int num_danes;
581
585 size_t rbuf_len;
586
590 size_t wbuf_len;
591
595 size_t io_len;
596
600 struct sockaddr_storage destination_address;
601
605 enum SocksPhase state;
606
610 uint16_t port;
611
615 struct HttpResponseHeader *header_head;
616
620 struct HttpResponseHeader *header_tail;
621
625 int ssl_checked;
626
630 int is_gns;
631
635 int is_tls;
636
640 int suspended;
641
645 int curl_paused;
646};
647
648
649/* *********************** Globals **************************** */
650
654static in_addr_t address;
655
659static struct in6_addr address6;
660
664static uint16_t port = GNUNET_GNS_PROXY_PORT;
665
669static char *cafile_opt;
670
674static struct GNUNET_NETWORK_Handle *lsock4;
675
679static struct GNUNET_NETWORK_Handle *lsock6;
680
684static struct GNUNET_SCHEDULER_Task *ltask4;
685
689static struct GNUNET_SCHEDULER_Task *ltask6;
690
694static struct GNUNET_SCHEDULER_Task *curl_download_task;
695
699static CURLM *curl_multi;
700
704static struct GNUNET_GNS_Handle *gns_handle;
705
709static int disable_v6;
710
714static struct MhdHttpList *mhd_httpd_head;
715
719static struct MhdHttpList *mhd_httpd_tail;
720
725static struct MhdHttpList *httpd;
726
730static struct Socks5Request *s5r_head;
731
735static struct Socks5Request *s5r_tail;
736
740static struct ProxyCA proxy_ca;
741
745static struct MHD_Response *curl_failure_response;
746
750static const struct GNUNET_CONFIGURATION_Handle *cfg;
751
752
753/* ************************* Global helpers ********************* */
754
755
761static void
762run_mhd_now (struct MhdHttpList *hd);
763
764
770static void
771cleanup_s5r (struct Socks5Request *s5r)
772{
773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
774 "Cleaning up socks request\n");
775 if (NULL != s5r->curl)
776 {
777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
778 "Cleaning up cURL handle\n");
779 curl_multi_remove_handle (curl_multi,
780 s5r->curl);
781 curl_easy_cleanup (s5r->curl);
782 s5r->curl = NULL;
783 }
784 if (s5r->suspended)
785 {
786 s5r->suspended = GNUNET_NO;
787 MHD_resume_connection (s5r->con);
788 }
789 curl_slist_free_all (s5r->headers);
790 if (NULL != s5r->hosts)
791 {
792 curl_slist_free_all (s5r->hosts);
793 }
794 if ((NULL != s5r->response) &&
795 (curl_failure_response != s5r->response))
796 {
797 MHD_destroy_response (s5r->response);
798 s5r->response = NULL;
799 }
800 if (NULL != s5r->rtask)
801 {
802 GNUNET_SCHEDULER_cancel (s5r->rtask);
803 s5r->rtask = NULL;
804 }
805 if (NULL != s5r->timeout_task)
806 {
807 GNUNET_SCHEDULER_cancel (s5r->timeout_task);
808 s5r->timeout_task = NULL;
809 }
810 if (NULL != s5r->wtask)
811 {
812 GNUNET_SCHEDULER_cancel (s5r->wtask);
813 s5r->wtask = NULL;
814 }
815 if (NULL != s5r->gns_lookup)
816 {
817 GNUNET_GNS_lookup_with_tld_cancel (s5r->gns_lookup);
818 s5r->gns_lookup = NULL;
819 }
820 if (NULL != s5r->sock)
821 {
822 if (SOCKS5_SOCKET_WITH_MHD <= s5r->state)
823 GNUNET_NETWORK_socket_free_memory_only_ (s5r->sock);
824 else
825 GNUNET_NETWORK_socket_close (s5r->sock);
826 s5r->sock = NULL;
827 }
828 GNUNET_CONTAINER_DLL_remove (s5r_head,
829 s5r_tail,
830 s5r);
831 GNUNET_free (s5r->domain);
832 GNUNET_free (s5r->leho);
833 GNUNET_free (s5r->url);
834 for (unsigned int i = 0; i < s5r->num_danes; i++)
835 GNUNET_free (s5r->dane_data[i]);
836 GNUNET_free (s5r);
837}
838
839
840/* ************************* HTTP handling with cURL *********************** */
841
842static void
843curl_download_prepare (void);
844
845
857static ssize_t
858mhd_content_cb (void *cls,
859 uint64_t pos,
860 char*buf,
861 size_t max)
862{
863 struct Socks5Request *s5r = cls;
864 size_t bytes_to_copy;
865
866 if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
867 (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
868 {
869 /* we're still not done with the upload, do not yet
870 start the download, the IO buffer is still full
871 with upload data. */
873 "Pausing MHD download %s%s, not yet ready for download\n",
874 s5r->domain,
875 s5r->url);
876 return 0; /* not yet ready for data download */
877 }
878 bytes_to_copy = GNUNET_MIN (max,
879 s5r->io_len);
880 if ((0 == bytes_to_copy) &&
881 (SOCKS5_SOCKET_DOWNLOAD_DONE != s5r->state))
882 {
884 "Pausing MHD download %s%s, no data available\n",
885 s5r->domain,
886 s5r->url);
887 if (NULL != s5r->curl)
888 {
890 "Continuing CURL interaction for %s%s\n",
891 s5r->domain,
892 s5r->url);
893 if (GNUNET_YES == s5r->curl_paused)
894 {
895 s5r->curl_paused = GNUNET_NO;
896 curl_easy_pause (s5r->curl,
897 CURLPAUSE_CONT);
898 }
900 }
901 if (GNUNET_NO == s5r->suspended)
902 {
903 MHD_suspend_connection (s5r->con);
904 s5r->suspended = GNUNET_YES;
905 }
906 return 0; /* more data later */
907 }
908 if ((0 == bytes_to_copy) &&
909 (SOCKS5_SOCKET_DOWNLOAD_DONE == s5r->state))
910 {
912 "Completed MHD download %s%s\n",
913 s5r->domain,
914 s5r->url);
915 return MHD_CONTENT_READER_END_OF_STREAM;
916 }
918 "Writing %llu/%llu bytes to %s%s\n",
919 (unsigned long long) bytes_to_copy,
920 (unsigned long long) s5r->io_len,
921 s5r->domain,
922 s5r->url);
923 GNUNET_memcpy (buf,
924 s5r->io_buf,
925 bytes_to_copy);
926 memmove (s5r->io_buf,
927 &s5r->io_buf[bytes_to_copy],
928 s5r->io_len - bytes_to_copy);
929 s5r->io_len -= bytes_to_copy;
930 if ((NULL != s5r->curl) &&
931 (GNUNET_YES == s5r->curl_paused))
932 {
934 "Continuing CURL interaction for %s%s\n",
935 s5r->domain,
936 s5r->url);
937 s5r->curl_paused = GNUNET_NO;
938 curl_easy_pause (s5r->curl,
939 CURLPAUSE_CONT);
940 }
941 return bytes_to_copy;
942}
943
944
953static int
955{
956 unsigned int cert_list_size;
957 const gnutls_datum_t *chainp;
958 const struct curl_tlssessioninfo *tlsinfo;
959 char certdn[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 3];
960 size_t size;
961 gnutls_x509_crt_t x509_cert;
962 int rc;
963 const char *name;
964
965 s5r->ssl_checked = GNUNET_YES;
967 "Checking X.509 certificate\n");
968 if (CURLE_OK !=
969 curl_easy_getinfo (s5r->curl,
970 CURLINFO_TLS_SSL_PTR,
971 &tlsinfo))
972 return GNUNET_SYSERR;
973 if (CURLSSLBACKEND_GNUTLS != tlsinfo->backend)
974 {
976 _ ("Unsupported CURL TLS backend %d\n"),
977 tlsinfo->backend);
978 return GNUNET_SYSERR;
979 }
980 chainp = gnutls_certificate_get_peers (tlsinfo->internals,
981 &cert_list_size);
982 if ((! chainp) ||
983 (0 == cert_list_size))
984 return GNUNET_SYSERR;
985
986 size = sizeof(certdn);
987 /* initialize an X.509 certificate structure. */
988 gnutls_x509_crt_init (&x509_cert);
989 gnutls_x509_crt_import (x509_cert,
990 chainp,
991 GNUTLS_X509_FMT_DER);
992
993 if (0 != (rc = gnutls_x509_crt_get_dn_by_oid (x509_cert,
994 GNUTLS_OID_X520_COMMON_NAME,
995 0, /* the first and only one */
996 0 /* no DER encoding */,
997 certdn,
998 &size)))
999 {
1001 _ ("Failed to fetch CN from cert: %s\n"),
1002 gnutls_strerror (rc));
1003 gnutls_x509_crt_deinit (x509_cert);
1004 return GNUNET_SYSERR;
1005 }
1006 /* check for TLSA/DANE records */
1007#if HAVE_GNUTLS_DANE
1008 if (0 != s5r->num_danes)
1009 {
1010 dane_state_t dane_state;
1011 dane_query_t dane_query;
1012 unsigned int verify;
1013
1014 /* FIXME: add flags to gnutls to NOT read UNBOUND_ROOT_KEY_FILE here! */
1015 if (0 != (rc = dane_state_init (&dane_state,
1016#ifdef DANE_F_IGNORE_DNSSEC
1017 DANE_F_IGNORE_DNSSEC |
1018#endif
1019 DANE_F_IGNORE_LOCAL_RESOLVER)))
1020 {
1022 _ ("Failed to initialize DANE: %s\n"),
1023 dane_strerror (rc));
1024 gnutls_x509_crt_deinit (x509_cert);
1025 return GNUNET_SYSERR;
1026 }
1027 s5r->dane_data[s5r->num_danes] = NULL;
1028 s5r->dane_data_len[s5r->num_danes] = 0;
1029 if (0 != (rc = dane_raw_tlsa (dane_state,
1030 &dane_query,
1031 s5r->dane_data,
1032 s5r->dane_data_len,
1033 GNUNET_YES,
1034 GNUNET_NO)))
1035 {
1037 _ ("Failed to parse DANE record: %s\n"),
1038 dane_strerror (rc));
1039 dane_state_deinit (dane_state);
1040 gnutls_x509_crt_deinit (x509_cert);
1041 return GNUNET_SYSERR;
1042 }
1043 if (0 != (rc = dane_verify_crt_raw (dane_state,
1044 chainp,
1045 cert_list_size,
1046 gnutls_certificate_type_get (
1047 tlsinfo->internals),
1048 dane_query,
1049 0, 0,
1050 &verify)))
1051 {
1053 _ ("Failed to verify TLS connection using DANE: %s\n"),
1054 dane_strerror (rc));
1055 dane_query_deinit (dane_query);
1056 dane_state_deinit (dane_state);
1057 gnutls_x509_crt_deinit (x509_cert);
1058 return GNUNET_SYSERR;
1059 }
1060 if (0 != verify)
1061 {
1063 _ (
1064 "Failed DANE verification failed with GnuTLS verify status code: %u\n"),
1065 verify);
1066 dane_query_deinit (dane_query);
1067 dane_state_deinit (dane_state);
1068 gnutls_x509_crt_deinit (x509_cert);
1069 return GNUNET_SYSERR;
1070 }
1071 dane_query_deinit (dane_query);
1072 dane_state_deinit (dane_state);
1073 /* success! */
1074 }
1075 else
1076#endif
1077 {
1078 /* try LEHO or ordinary domain name X509 verification */
1079 name = s5r->domain;
1080 if (NULL != s5r->leho)
1081 name = s5r->leho;
1082 if (NULL != name)
1083 {
1084 if (0 == (rc = gnutls_x509_crt_check_hostname (x509_cert,
1085 name)))
1086 {
1088 _ (
1089 "TLS certificate subject name (%s) does not match `%s': %d\n"),
1090 certdn,
1091 name,
1092 rc);
1093 gnutls_x509_crt_deinit (x509_cert);
1094 return GNUNET_SYSERR;
1095 }
1096 }
1097 else
1098 {
1099 /* we did not even have the domain name!? */
1100 GNUNET_break (0);
1101 return GNUNET_SYSERR;
1102 }
1103 }
1104 gnutls_x509_crt_deinit (x509_cert);
1105 return GNUNET_OK;
1106}
1107
1108
1121static size_t
1122curl_check_hdr (void *buffer,
1123 size_t size,
1124 size_t nmemb,
1125 void *cls)
1126{
1127 struct Socks5Request *s5r = cls;
1128 struct HttpResponseHeader *header;
1129 size_t bytes = size * nmemb;
1130 char *ndup;
1131 const char *hdr_type;
1132 const char *cookie_domain;
1133 char *hdr_val;
1134 char *new_cookie_hdr;
1135 char *new_location;
1136 size_t offset;
1137 size_t delta_cdomain;
1138 int domain_matched;
1139 char *tok;
1140
1142 "Receiving HTTP response header from CURL\n");
1143 /* first, check TLS certificate */
1144 if ((GNUNET_YES != s5r->ssl_checked) &&
1145 (GNUNET_YES == s5r->is_tls))
1146 // (HTTPS_PORT == s5r->port))
1147 {
1148 if (GNUNET_OK != check_ssl_certificate (s5r))
1149 return 0;
1150 }
1151 ndup = GNUNET_strndup (buffer,
1152 bytes);
1153 hdr_type = strtok (ndup,
1154 ":");
1155 if (NULL == hdr_type)
1156 {
1157 GNUNET_free (ndup);
1158 return bytes;
1159 }
1160 hdr_val = strtok (NULL,
1161 "");
1162 if (NULL == hdr_val)
1163 {
1164 GNUNET_free (ndup);
1165 return bytes;
1166 }
1167 if (' ' == *hdr_val)
1168 hdr_val++;
1169
1170 /* custom logic for certain header types */
1171 new_cookie_hdr = NULL;
1172 if ((NULL != s5r->leho) &&
1173 (0 == strcasecmp (hdr_type,
1174 MHD_HTTP_HEADER_SET_COOKIE)))
1175
1176 {
1177 new_cookie_hdr = GNUNET_malloc (strlen (hdr_val)
1178 + strlen (s5r->domain) + 1);
1179 offset = 0;
1180 domain_matched = GNUNET_NO; /* make sure we match domain at most once */
1181 for (tok = strtok (hdr_val, ";"); NULL != tok; tok = strtok (NULL, ";"))
1182 {
1183 if ((0 == strncasecmp (tok,
1184 " domain",
1185 strlen (" domain"))) &&
1186 (GNUNET_NO == domain_matched))
1187 {
1188 domain_matched = GNUNET_YES;
1189 cookie_domain = tok + strlen (" domain") + 1;
1190 if (strlen (cookie_domain) < strlen (s5r->leho))
1191 {
1192 delta_cdomain = strlen (s5r->leho) - strlen (cookie_domain);
1193 if (0 == strcasecmp (cookie_domain,
1194 s5r->leho + delta_cdomain))
1195 {
1196 offset += sprintf (new_cookie_hdr + offset,
1197 " domain=%s;",
1198 s5r->domain);
1199 continue;
1200 }
1201 }
1202 else if (0 == strcmp (cookie_domain,
1203 s5r->leho))
1204 {
1205 offset += sprintf (new_cookie_hdr + offset,
1206 " domain=%s;",
1207 s5r->domain);
1208 continue;
1209 }
1210 else if (('.' == cookie_domain[0]) &&
1211 (0 == strcmp (&cookie_domain[1],
1212 s5r->leho)))
1213 {
1214 offset += sprintf (new_cookie_hdr + offset,
1215 " domain=.%s;",
1216 s5r->domain);
1217 continue;
1218 }
1220 _ ("Cookie domain `%s' supplied by server is invalid\n"),
1221 tok);
1222 }
1223 GNUNET_memcpy (new_cookie_hdr + offset,
1224 tok,
1225 strlen (tok));
1226 offset += strlen (tok);
1227 new_cookie_hdr[offset++] = ';';
1228 }
1229 hdr_val = new_cookie_hdr;
1230 hdr_val[offset] = '\0';
1231 }
1232
1233 new_location = NULL;
1234 if (0 == strcasecmp (MHD_HTTP_HEADER_TRANSFER_ENCODING,
1235 hdr_type))
1236 {
1237 /* Ignore transfer encoding, set automatically by MHD if required */
1238 goto cleanup;
1239 }
1240 if ((0 == strcasecmp (MHD_HTTP_HEADER_LOCATION,
1241 hdr_type)))
1242 {
1243 char *leho_host;
1244
1245 GNUNET_asprintf (&leho_host,
1246 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1247 ? "http://%s"
1248 : "https://%s",
1249 s5r->leho);
1250 if (0 == strncmp (leho_host,
1251 hdr_val,
1252 strlen (leho_host)))
1253 {
1254 GNUNET_asprintf (&new_location,
1255 "%s%s%s",
1256 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1257 ? "http://"
1258 : "https://",
1259 s5r->domain,
1260 hdr_val + strlen (leho_host));
1261 hdr_val = new_location;
1262 }
1263 GNUNET_free (leho_host);
1264 }
1265 else if (0 == strcasecmp (MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
1266 hdr_type))
1267 {
1268 char *leho_host;
1269
1270 GNUNET_asprintf (&leho_host,
1271 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1272 ? "http://%s"
1273 : "https://%s",
1274 s5r->leho);
1275 if (0 == strncmp (leho_host,
1276 hdr_val,
1277 strlen (leho_host)))
1278 {
1279 GNUNET_asprintf (&new_location,
1280 "%s%s",
1281 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1282 ? "http://"
1283 : "https://",
1284 s5r->domain);
1285 hdr_val = new_location;
1286 }
1287 GNUNET_free (leho_host);
1288 }
1289
1290 /* MHD does not allow certain characters in values, remove those */
1291 if (NULL != (tok = strchr (hdr_val, '\n')))
1292 *tok = '\0';
1293 if (NULL != (tok = strchr (hdr_val, '\r')))
1294 *tok = '\0';
1295 if (NULL != (tok = strchr (hdr_val, '\t')))
1296 *tok = '\0';
1297 if (0 != strlen (hdr_val)) /* Rely in MHD to set those */
1298 {
1300 "Adding header %s: %s to MHD response\n",
1301 hdr_type,
1302 hdr_val);
1303 header = GNUNET_new (struct HttpResponseHeader);
1304 header->type = GNUNET_strdup (hdr_type);
1305 header->value = GNUNET_strdup (hdr_val);
1307 s5r->header_tail,
1308 header);
1309 }
1310cleanup:
1311 GNUNET_free (ndup);
1312 GNUNET_free (new_cookie_hdr);
1313 GNUNET_free (new_location);
1314 return bytes;
1315}
1316
1317
1326static int
1328{
1329 long resp_code;
1330 double content_length;
1331
1332 if (NULL != s5r->response)
1333 {
1335 "Response already set!\n");
1336 return GNUNET_SYSERR;
1337 }
1338
1339 GNUNET_break (CURLE_OK ==
1340 curl_easy_getinfo (s5r->curl,
1341 CURLINFO_RESPONSE_CODE,
1342 &resp_code));
1343 GNUNET_break (CURLE_OK ==
1344 curl_easy_getinfo (s5r->curl,
1345 CURLINFO_CONTENT_LENGTH_DOWNLOAD_T,
1346 &content_length));
1348 "Creating MHD response with code %d and size %d for %s%s\n",
1349 (int) resp_code,
1350 (int) content_length,
1351 s5r->domain,
1352 s5r->url);
1353 s5r->response_code = resp_code;
1354 s5r->response = MHD_create_response_from_callback ((0 > content_length)
1355 ? MHD_SIZE_UNKNOWN
1356 : content_length,
1359 s5r,
1360 NULL);
1361 for (struct HttpResponseHeader *header = s5r->header_head;
1362 NULL != header;
1363 header = header->next)
1364 {
1365 if (0 == strcasecmp (header->type,
1366 MHD_HTTP_HEADER_CONTENT_LENGTH))
1367 continue; /* MHD won't let us mess with those, for good reason */
1368 if ((0 == strcasecmp (header->type,
1369 MHD_HTTP_HEADER_TRANSFER_ENCODING)) &&
1370 ((0 == strcasecmp (header->value,
1371 "identity")) ||
1372 (0 == strcasecmp (header->value,
1373 "chunked"))))
1374 continue; /* MHD won't let us mess with those, for good reason */
1375 if (MHD_YES !=
1376 MHD_add_response_header (s5r->response,
1377 header->type,
1378 header->value))
1379 {
1380 GNUNET_break (0);
1382 "Failed to add header `%s:%s'\n",
1383 header->type,
1384 header->value);
1385 }
1386 }
1387 /* force connection to be closed after each request, as we
1388 do not support HTTP pipelining (yet, FIXME!) */
1389 /*GNUNET_break (MHD_YES ==
1390 MHD_add_response_header (s5r->response,
1391 MHD_HTTP_HEADER_CONNECTION,
1392 "close"));*/
1393 MHD_resume_connection (s5r->con);
1394 s5r->suspended = GNUNET_NO;
1395 return GNUNET_OK;
1396}
1397
1398
1409static size_t
1410curl_download_cb (void *ptr,
1411 size_t size,
1412 size_t nmemb,
1413 void*ctx)
1414{
1415 struct Socks5Request *s5r = ctx;
1416 size_t total = size * nmemb;
1417
1419 "Receiving %ux%u bytes for `%s%s' from cURL to download\n",
1420 (unsigned int) size,
1421 (unsigned int) nmemb,
1422 s5r->domain,
1423 s5r->url);
1424 if (NULL == s5r->response)
1427 if ((SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) &&
1428 (0 == s5r->io_len))
1429 {
1431 "Previous upload finished... starting DOWNLOAD.\n");
1433 }
1434 if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
1436 {
1437 /* we're still not done with the upload, do not yet
1438 start the download, the IO buffer is still full
1439 with upload data. */
1441 "Pausing CURL download `%s%s', waiting for UPLOAD to finish\n",
1442 s5r->domain,
1443 s5r->url);
1444 s5r->curl_paused = GNUNET_YES;
1445 return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */
1446 }
1447 if (sizeof(s5r->io_buf) - s5r->io_len < total)
1448 {
1450 "Pausing CURL `%s%s' download, not enough space %llu %llu %llu\n",
1451 s5r->domain,
1452 s5r->url,
1453 (unsigned long long) sizeof(s5r->io_buf),
1454 (unsigned long long) s5r->io_len,
1455 (unsigned long long) total);
1456 s5r->curl_paused = GNUNET_YES;
1457 return CURL_WRITEFUNC_PAUSE; /* not enough space */
1458 }
1459 GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
1460 ptr,
1461 total);
1462 s5r->io_len += total;
1463 if (GNUNET_YES == s5r->suspended)
1464 {
1465 MHD_resume_connection (s5r->con);
1466 s5r->suspended = GNUNET_NO;
1467 }
1469 "Received %llu bytes of payload via cURL from %s\n",
1470 (unsigned long long) total,
1471 s5r->domain);
1472 if (s5r->io_len == total)
1473 run_mhd_now (s5r->hd);
1474 return total;
1475}
1476
1477
1488static size_t
1489curl_upload_cb (void *buf,
1490 size_t size,
1491 size_t nmemb,
1492 void *cls)
1493{
1494 struct Socks5Request *s5r = cls;
1495 size_t len = size * nmemb;
1496 size_t to_copy;
1497
1499 "Receiving %ux%u bytes for `%s%s' from cURL to upload\n",
1500 (unsigned int) size,
1501 (unsigned int) nmemb,
1502 s5r->domain,
1503 s5r->url);
1504
1505 if ((0 == s5r->io_len) &&
1507 {
1509 "Pausing CURL UPLOAD %s%s, need more data\n",
1510 s5r->domain,
1511 s5r->url);
1512 return CURL_READFUNC_PAUSE;
1513 }
1514 if ((0 == s5r->io_len) &&
1516 {
1518 if (GNUNET_YES == s5r->curl_paused)
1519 {
1520 s5r->curl_paused = GNUNET_NO;
1521 curl_easy_pause (s5r->curl,
1522 CURLPAUSE_CONT);
1523 }
1525 "Completed CURL UPLOAD %s%s\n",
1526 s5r->domain,
1527 s5r->url);
1528 return 0; /* upload finished, can now download */
1529 }
1530 if ((SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) &&
1532 {
1533 GNUNET_break (0);
1534 return CURL_READFUNC_ABORT;
1535 }
1536 to_copy = GNUNET_MIN (s5r->io_len,
1537 len);
1538 GNUNET_memcpy (buf,
1539 s5r->io_buf,
1540 to_copy);
1541 memmove (s5r->io_buf,
1542 &s5r->io_buf[to_copy],
1543 s5r->io_len - to_copy);
1544 s5r->io_len -= to_copy;
1545 if (s5r->io_len + to_copy == sizeof(s5r->io_buf))
1546 run_mhd_now (s5r->hd); /* got more space for upload now */
1547 return to_copy;
1548}
1549
1550
1551/* ************************** main loop of cURL interaction ****************** */
1552
1553
1560static void
1561curl_task_download (void *cls);
1562
1563
1567static void
1569{
1570 CURLMcode mret;
1571 fd_set rs;
1572 fd_set ws;
1573 fd_set es;
1574 int max;
1575 struct GNUNET_NETWORK_FDSet *grs;
1576 struct GNUNET_NETWORK_FDSet *gws;
1577 long to;
1578 struct GNUNET_TIME_Relative rtime;
1579
1581 "Scheduling CURL interaction\n");
1582 if (NULL != curl_download_task)
1583 {
1585 curl_download_task = NULL;
1586 }
1587 max = -1;
1588 FD_ZERO (&rs);
1589 FD_ZERO (&ws);
1590 FD_ZERO (&es);
1591 if (CURLM_OK != (mret = curl_multi_fdset (curl_multi,
1592 &rs,
1593 &ws,
1594 &es,
1595 &max)))
1596 {
1598 "%s failed at %s:%d: `%s'\n",
1599 "curl_multi_fdset", __FILE__, __LINE__,
1600 curl_multi_strerror (mret));
1601 return;
1602 }
1603 to = -1;
1604 GNUNET_break (CURLM_OK ==
1605 curl_multi_timeout (curl_multi,
1606 &to));
1607 if (-1 == to)
1609 else
1611 to);
1612 if (-1 != max)
1613 {
1617 &rs,
1618 max + 1);
1620 &ws,
1621 max + 1);
1624 rtime,
1625 grs,
1626 gws,
1628 curl_multi);
1631 }
1632 else
1633 {
1636 curl_multi);
1637 }
1638}
1639
1640
1646static void
1647curl_task_download (void *cls)
1648{
1649 int running;
1650 int msgnum;
1651 struct CURLMsg *msg;
1652 CURLMcode mret;
1653 struct Socks5Request *s5r;
1654
1655 curl_download_task = NULL;
1657 "Running CURL interaction\n");
1658 do
1659 {
1660 running = 0;
1661 mret = curl_multi_perform (curl_multi,
1662 &running);
1664 "Checking CURL multi status: %d\n",
1665 mret);
1666 while (NULL != (msg = curl_multi_info_read (curl_multi,
1667 &msgnum)))
1668 {
1669 GNUNET_break (CURLE_OK ==
1670 curl_easy_getinfo (msg->easy_handle,
1671 CURLINFO_PRIVATE,
1672 (char **) &s5r));
1673 if (NULL == s5r)
1674 {
1675 GNUNET_break (0);
1676 continue;
1677 }
1678 switch (msg->msg)
1679 {
1680 case CURLMSG_NONE:
1681 /* documentation says this is not used */
1682 GNUNET_break (0);
1683 break;
1684
1685 case CURLMSG_DONE:
1686 switch (msg->data.result)
1687 {
1688 case CURLE_OK:
1689 case CURLE_GOT_NOTHING:
1691 "CURL download %s%s completed.\n",
1692 s5r->domain,
1693 s5r->url);
1694 if (NULL == s5r->response)
1695 {
1698 }
1700 if (GNUNET_YES == s5r->suspended)
1701 {
1702 MHD_resume_connection (s5r->con);
1703 s5r->suspended = GNUNET_NO;
1704 }
1705 run_mhd_now (s5r->hd);
1706 break;
1707
1708 default:
1710 "Download curl %s%s failed: %s\n",
1711 s5r->domain,
1712 s5r->url,
1713 curl_easy_strerror (msg->data.result));
1714 /* FIXME: indicate error somehow? close MHD connection badly as well? */
1716 if (GNUNET_YES == s5r->suspended)
1717 {
1718 MHD_resume_connection (s5r->con);
1719 s5r->suspended = GNUNET_NO;
1720 }
1721 run_mhd_now (s5r->hd);
1722 break;
1723 }
1724 if (NULL == s5r->response)
1726 break;
1727
1728 case CURLMSG_LAST:
1729 /* documentation says this is not used */
1730 GNUNET_break (0);
1731 break;
1732
1733 default:
1734 /* unexpected status code */
1735 GNUNET_break (0);
1736 break;
1737 }
1738 }
1739 ;
1740 }
1741 while (mret == CURLM_CALL_MULTI_PERFORM);
1742 if (CURLM_OK != mret)
1744 "%s failed at %s:%d: `%s'\n",
1745 "curl_multi_perform", __FILE__, __LINE__,
1746 curl_multi_strerror (mret));
1747 if (0 == running)
1748 {
1750 "Suspending cURL multi loop, no more events pending\n");
1751 if (NULL != curl_download_task)
1752 {
1754 curl_download_task = NULL;
1755 }
1756 return; /* nothing more in progress */
1757 }
1759}
1760
1761
1762/* ********************************* MHD response generation ******************* */
1763
1764
1778static int
1779con_val_iter (void *cls,
1780 enum MHD_ValueKind kind,
1781 const char *key,
1782 const char *value)
1783{
1784 struct Socks5Request *s5r = cls;
1785 char *hdr;
1786
1787 if ((0 == strcasecmp (MHD_HTTP_HEADER_HOST,
1788 key)) &&
1789 (NULL != s5r->leho))
1790 value = s5r->leho;
1791 GNUNET_asprintf (&hdr,
1792 "%s: %s",
1793 key,
1794 value);
1796 "Adding HEADER `%s' to HTTP request\n",
1797 hdr);
1798 s5r->headers = curl_slist_append (s5r->headers,
1799 hdr);
1800 GNUNET_free (hdr);
1801 return MHD_YES;
1802}
1803
1804
1828static MHD_RESULT
1829create_response (void *cls,
1830 struct MHD_Connection *con,
1831 const char *url,
1832 const char *meth,
1833 const char *ver,
1834 const char *upload_data,
1835 size_t *upload_data_size,
1836 void **con_cls)
1837{
1838 struct Socks5Request *s5r = *con_cls;
1839 char *curlurl;
1840 char ipstring[INET6_ADDRSTRLEN];
1841 char ipaddr[INET6_ADDRSTRLEN + 2];
1842 char *curl_hosts;
1843 const struct sockaddr *sa;
1844 const struct sockaddr_in *s4;
1845 const struct sockaddr_in6 *s6;
1846 uint16_t port_tmp;
1847 size_t left;
1848
1849 if (NULL == s5r)
1850 {
1851 GNUNET_break (0);
1852 return MHD_NO;
1853 }
1854 s5r->con = con;
1855 /* Fresh connection. */
1856 if (SOCKS5_SOCKET_WITH_MHD == s5r->state)
1857 {
1858 /* first time here, initialize curl handle */
1859 if (s5r->is_gns)
1860 {
1861 sa = (const struct sockaddr *) &s5r->destination_address;
1862 switch (sa->sa_family)
1863 {
1864 case AF_INET:
1865 s4 = (const struct sockaddr_in *) &s5r->destination_address;
1866 if (NULL == inet_ntop (AF_INET,
1867 &s4->sin_addr,
1868 ipstring,
1869 sizeof(ipstring)))
1870 {
1871 GNUNET_break (0);
1872 return MHD_NO;
1873 }
1874 GNUNET_snprintf (ipaddr,
1875 sizeof(ipaddr),
1876 "%s",
1877 ipstring);
1878 port_tmp = ntohs (s4->sin_port);
1879 break;
1880
1881 case AF_INET6:
1882 s6 = (const struct sockaddr_in6 *) &s5r->destination_address;
1883 if (NULL == inet_ntop (AF_INET6,
1884 &s6->sin6_addr,
1885 ipstring,
1886 sizeof(ipstring)))
1887 {
1888 GNUNET_break (0);
1889 return MHD_NO;
1890 }
1891 GNUNET_snprintf (ipaddr,
1892 sizeof(ipaddr),
1893 "%s",
1894 ipstring);
1895 port_tmp = ntohs (s6->sin6_port);
1896 break;
1897
1898 default:
1899 GNUNET_break (0);
1900 return MHD_NO;
1901 }
1902 GNUNET_asprintf (&curl_hosts,
1903 "%s:%d:%s",
1904 s5r->leho,
1905 port_tmp,
1906 ipaddr);
1907 s5r->hosts = curl_slist_append (NULL,
1908 curl_hosts);
1909 GNUNET_free (curl_hosts);
1910 }
1911 else
1912 {
1913 port_tmp = s5r->port;
1914 }
1915 if (NULL == s5r->curl)
1916 s5r->curl = curl_easy_init ();
1917 if (NULL == s5r->curl)
1918 return MHD_queue_response (con,
1919 MHD_HTTP_INTERNAL_SERVER_ERROR,
1921 curl_easy_setopt (s5r->curl,
1922 CURLOPT_HEADERFUNCTION,
1924 curl_easy_setopt (s5r->curl,
1925 CURLOPT_HEADERDATA,
1926 s5r);
1927 curl_easy_setopt (s5r->curl,
1928 CURLOPT_FOLLOWLOCATION,
1929 0);
1930 if (s5r->is_gns)
1931 curl_easy_setopt (s5r->curl,
1932 CURLOPT_IPRESOLVE,
1933 CURL_IPRESOLVE_V4);
1934 curl_easy_setopt (s5r->curl,
1935 CURLOPT_CONNECTTIMEOUT,
1936 600L);
1937 curl_easy_setopt (s5r->curl,
1938 CURLOPT_TIMEOUT,
1939 600L);
1940 curl_easy_setopt (s5r->curl,
1941 CURLOPT_NOSIGNAL,
1942 1L);
1943 curl_easy_setopt (s5r->curl,
1944 CURLOPT_HTTP_CONTENT_DECODING,
1945 0);
1946 curl_easy_setopt (s5r->curl,
1947 CURLOPT_NOSIGNAL,
1948 1L);
1949 curl_easy_setopt (s5r->curl,
1950 CURLOPT_PRIVATE,
1951 s5r);
1952 curl_easy_setopt (s5r->curl,
1953 CURLOPT_VERBOSE,
1954 0L);
1960 if ((NULL != s5r->leho) &&
1961 (NULL != s5r->hosts))
1962 {
1963 curl_easy_setopt (s5r->curl,
1964 CURLOPT_RESOLVE,
1965 s5r->hosts);
1966 }
1967 if (s5r->is_gns)
1968 {
1969 GNUNET_asprintf (&curlurl,
1970 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1971 ? "http://%s:%d%s"
1972 : "https://%s:%d%s",
1973 (NULL != s5r->leho)
1974 ? s5r->leho
1975 : ipaddr,
1976 port_tmp,
1977 s5r->url);
1978 }
1979 else
1980 {
1981 GNUNET_asprintf (&curlurl,
1982 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1983 ? "http://%s:%d%s"
1984 : "https://%s:%d%s",
1985 s5r->domain,
1986 port_tmp,
1987 s5r->url);
1988 }
1989 curl_easy_setopt (s5r->curl,
1990 CURLOPT_URL,
1991 curlurl);
1993 "Launching %s CURL interaction, fetching `%s'\n",
1994 (s5r->is_gns) ? "GNS" : "DNS",
1995 curlurl);
1996 GNUNET_free (curlurl);
1997 if (0 == strcasecmp (meth,
1998 MHD_HTTP_METHOD_PUT))
1999 {
2001 curl_easy_setopt (s5r->curl,
2002 CURLOPT_UPLOAD,
2003 1L);
2004 curl_easy_setopt (s5r->curl,
2005 CURLOPT_WRITEFUNCTION,
2007 curl_easy_setopt (s5r->curl,
2008 CURLOPT_WRITEDATA,
2009 s5r);
2010 GNUNET_assert (CURLE_OK ==
2011 curl_easy_setopt (s5r->curl,
2012 CURLOPT_READFUNCTION,
2013 &curl_upload_cb));
2014 curl_easy_setopt (s5r->curl,
2015 CURLOPT_READDATA,
2016 s5r);
2017 {
2018 const char *us;
2019 long upload_size = 0;
2020
2021 us = MHD_lookup_connection_value (con,
2022 MHD_HEADER_KIND,
2023 MHD_HTTP_HEADER_CONTENT_LENGTH);
2024 if ((1 == sscanf (us,
2025 "%ld",
2026 &upload_size)) &&
2027 (upload_size >= 0))
2028 {
2029 curl_easy_setopt (s5r->curl,
2030 CURLOPT_INFILESIZE,
2031 upload_size);
2032 }
2033 }
2034 }
2035 else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_POST))
2036 {
2038 curl_easy_setopt (s5r->curl,
2039 CURLOPT_POST,
2040 1L);
2041 curl_easy_setopt (s5r->curl,
2042 CURLOPT_WRITEFUNCTION,
2044 curl_easy_setopt (s5r->curl,
2045 CURLOPT_WRITEDATA,
2046 s5r);
2047 curl_easy_setopt (s5r->curl,
2048 CURLOPT_READFUNCTION,
2050 curl_easy_setopt (s5r->curl,
2051 CURLOPT_READDATA,
2052 s5r);
2053 {
2054 const char *us;
2055 long upload_size;
2056
2057 upload_size = 0;
2058 us = MHD_lookup_connection_value (con,
2059 MHD_HEADER_KIND,
2060 MHD_HTTP_HEADER_CONTENT_LENGTH);
2061 if ((NULL != us) &&
2062 (1 == sscanf (us,
2063 "%ld",
2064 &upload_size)) &&
2065 (upload_size >= 0))
2066 {
2067 curl_easy_setopt (s5r->curl,
2068 CURLOPT_INFILESIZE,
2069 upload_size);
2070 }
2071 else
2072 {
2073 curl_easy_setopt (s5r->curl,
2074 CURLOPT_INFILESIZE,
2075 upload_size);
2076 }
2077 }
2078 }
2079 else if (0 == strcasecmp (meth,
2080 MHD_HTTP_METHOD_HEAD))
2081 {
2083 curl_easy_setopt (s5r->curl,
2084 CURLOPT_NOBODY,
2085 1L);
2086 }
2087 else if (0 == strcasecmp (meth,
2088 MHD_HTTP_METHOD_OPTIONS))
2089 {
2091 curl_easy_setopt (s5r->curl,
2092 CURLOPT_CUSTOMREQUEST,
2093 "OPTIONS");
2094 curl_easy_setopt (s5r->curl,
2095 CURLOPT_WRITEFUNCTION,
2097 curl_easy_setopt (s5r->curl,
2098 CURLOPT_WRITEDATA,
2099 s5r);
2100 }
2101 else if (0 == strcasecmp (meth,
2102 MHD_HTTP_METHOD_GET))
2103 {
2105 curl_easy_setopt (s5r->curl,
2106 CURLOPT_HTTPGET,
2107 1L);
2108 curl_easy_setopt (s5r->curl,
2109 CURLOPT_WRITEFUNCTION,
2111 curl_easy_setopt (s5r->curl,
2112 CURLOPT_WRITEDATA,
2113 s5r);
2114 }
2115 else if (0 == strcasecmp (meth,
2116 MHD_HTTP_METHOD_DELETE))
2117 {
2119 curl_easy_setopt (s5r->curl,
2120 CURLOPT_CUSTOMREQUEST,
2121 "DELETE");
2122 curl_easy_setopt (s5r->curl,
2123 CURLOPT_WRITEFUNCTION,
2125 curl_easy_setopt (s5r->curl,
2126 CURLOPT_WRITEDATA,
2127 s5r);
2128 }
2129 else
2130 {
2132 _ ("Unsupported HTTP method `%s'\n"),
2133 meth);
2134 curl_easy_cleanup (s5r->curl);
2135 s5r->curl = NULL;
2136 return MHD_NO;
2137 }
2138
2139 if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_0))
2140 {
2141 curl_easy_setopt (s5r->curl,
2142 CURLOPT_HTTP_VERSION,
2143 CURL_HTTP_VERSION_1_0);
2144 }
2145 else if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_1))
2146 {
2147 curl_easy_setopt (s5r->curl,
2148 CURLOPT_HTTP_VERSION,
2149 CURL_HTTP_VERSION_1_1);
2150 }
2151 else
2152 {
2153 curl_easy_setopt (s5r->curl,
2154 CURLOPT_HTTP_VERSION,
2155 CURL_HTTP_VERSION_NONE);
2156 }
2157
2158 if (GNUNET_YES == s5r->is_tls) // (HTTPS_PORT == s5r->port)
2159 {
2160 curl_easy_setopt (s5r->curl,
2161 CURLOPT_USE_SSL,
2162 CURLUSESSL_ALL);
2163 if (0 < s5r->num_danes)
2164 curl_easy_setopt (s5r->curl,
2165 CURLOPT_SSL_VERIFYPEER,
2166 0L);
2167 else
2168 curl_easy_setopt (s5r->curl,
2169 CURLOPT_SSL_VERIFYPEER,
2170 1L);
2171 /* Disable cURL checking the hostname, as we will check ourselves
2172 as only we have the domain name or the LEHO or the DANE record */
2173 curl_easy_setopt (s5r->curl,
2174 CURLOPT_SSL_VERIFYHOST,
2175 0L);
2176 }
2177 else
2178 {
2179 curl_easy_setopt (s5r->curl,
2180 CURLOPT_USE_SSL,
2181 CURLUSESSL_NONE);
2182 }
2183
2184 if (CURLM_OK !=
2185 curl_multi_add_handle (curl_multi,
2186 s5r->curl))
2187 {
2188 GNUNET_break (0);
2189 curl_easy_cleanup (s5r->curl);
2190 s5r->curl = NULL;
2191 return MHD_NO;
2192 }
2193 MHD_get_connection_values (con,
2194 MHD_HEADER_KIND,
2195 (MHD_KeyValueIterator) & con_val_iter,
2196 s5r);
2197 curl_easy_setopt (s5r->curl,
2198 CURLOPT_HTTPHEADER,
2199 s5r->headers);
2201 return MHD_YES;
2202 }
2203
2204 /* continuing to process request */
2205 if (0 != *upload_data_size)
2206 {
2208 "Processing %u bytes UPLOAD\n",
2209 (unsigned int) *upload_data_size);
2210
2211 /* FIXME: This must be set or a header with Transfer-Encoding: chunked. Else
2212 * upload callback is not called!
2213 */
2214 curl_easy_setopt (s5r->curl,
2215 CURLOPT_POSTFIELDSIZE,
2216 *upload_data_size);
2217
2218 left = GNUNET_MIN (*upload_data_size,
2219 sizeof(s5r->io_buf) - s5r->io_len);
2220 GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
2221 upload_data,
2222 left);
2223 s5r->io_len += left;
2224 *upload_data_size -= left;
2225 GNUNET_assert (NULL != s5r->curl);
2226 if (GNUNET_YES == s5r->curl_paused)
2227 {
2228 s5r->curl_paused = GNUNET_NO;
2229 curl_easy_pause (s5r->curl,
2230 CURLPAUSE_CONT);
2231 }
2232 return MHD_YES;
2233 }
2235 {
2237 "Finished processing UPLOAD\n");
2239 }
2240 if (NULL == s5r->response)
2241 {
2243 "Waiting for HTTP response for %s%s...\n",
2244 s5r->domain,
2245 s5r->url);
2246 MHD_suspend_connection (con);
2247 s5r->suspended = GNUNET_YES;
2248 return MHD_YES;
2249 }
2251 "Queueing response for %s%s with MHD\n",
2252 s5r->domain,
2253 s5r->url);
2254 run_mhd_now (s5r->hd);
2255 return MHD_queue_response (con,
2256 s5r->response_code,
2257 s5r->response);
2258}
2259
2260
2261/* ******************** MHD HTTP setup and event loop ******************** */
2262
2263
2273static void
2274mhd_completed_cb (void *cls,
2275 struct MHD_Connection *connection,
2276 void **con_cls,
2277 enum MHD_RequestTerminationCode toe)
2278{
2279 struct Socks5Request *s5r = *con_cls;
2280
2281 if (NULL == s5r)
2282 return;
2283 if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
2285 "MHD encountered error handling request: %d\n",
2286 toe);
2287 if (NULL != s5r->curl)
2288 {
2290 "Removing cURL handle (MHD interaction complete)\n");
2291 curl_multi_remove_handle (curl_multi,
2292 s5r->curl);
2293 curl_slist_free_all (s5r->headers);
2294 s5r->headers = NULL;
2295 curl_easy_reset (s5r->curl);
2296 s5r->rbuf_len = 0;
2297 s5r->wbuf_len = 0;
2298 s5r->io_len = 0;
2300 }
2301 if ((NULL != s5r->response) &&
2303 MHD_destroy_response (s5r->response);
2304 for (struct HttpResponseHeader *header = s5r->header_head;
2305 NULL != header;
2306 header = s5r->header_head)
2307 {
2309 s5r->header_tail,
2310 header);
2311 GNUNET_free (header->type);
2312 GNUNET_free (header->value);
2313 GNUNET_free (header);
2314 }
2316 "Finished request for %s\n",
2317 s5r->url);
2318 GNUNET_free (s5r->url);
2320 s5r->url = NULL;
2321 s5r->response = NULL;
2322 *con_cls = NULL;
2323}
2324
2325
2335static void
2336mhd_connection_cb (void *cls,
2337 struct MHD_Connection *connection,
2338 void **con_cls,
2339 enum MHD_ConnectionNotificationCode cnc)
2340{
2341 struct Socks5Request *s5r;
2342 const union MHD_ConnectionInfo *ci;
2343 int sock;
2344
2345 switch (cnc)
2346 {
2347 case MHD_CONNECTION_NOTIFY_STARTED:
2348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
2349 ci = MHD_get_connection_info (connection,
2350 MHD_CONNECTION_INFO_CONNECTION_FD);
2351 if (NULL == ci)
2352 {
2353 GNUNET_break (0);
2354 return;
2355 }
2356 sock = ci->connect_fd;
2357 for (s5r = s5r_head; NULL != s5r; s5r = s5r->next)
2358 {
2359 if (GNUNET_NETWORK_get_fd (s5r->sock) == sock)
2360 {
2362 "Context set...\n");
2363 s5r->ssl_checked = GNUNET_NO;
2364 *con_cls = s5r;
2365 break;
2366 }
2367 }
2368 break;
2369
2370 case MHD_CONNECTION_NOTIFY_CLOSED:
2372 "Connection closed... cleaning up\n");
2373 s5r = *con_cls;
2374 if (NULL == s5r)
2375 {
2377 "Connection stale!\n");
2378 return;
2379 }
2380 cleanup_s5r (s5r);
2382 *con_cls = NULL;
2383 break;
2384
2385 default:
2386 GNUNET_break (0);
2387 }
2388}
2389
2390
2404static void *
2405mhd_log_callback (void *cls,
2406 const char *url,
2407 struct MHD_Connection *connection)
2408{
2409 struct Socks5Request *s5r;
2410 const union MHD_ConnectionInfo *ci;
2411
2412 ci = MHD_get_connection_info (connection,
2413 MHD_CONNECTION_INFO_SOCKET_CONTEXT);
2414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
2415 if (NULL == ci)
2416 {
2417 GNUNET_break (0);
2418 return NULL;
2419 }
2420 s5r = ci->socket_context;
2421 if (NULL != s5r->url)
2422 {
2423 GNUNET_break (0);
2424 return NULL;
2425 }
2426 s5r->url = GNUNET_strdup (url);
2427 if (NULL != s5r->timeout_task)
2428 {
2430 s5r->timeout_task = NULL;
2431 }
2433 return s5r;
2434}
2435
2436
2442static void
2443kill_httpd (struct MhdHttpList *hd)
2444{
2447 hd);
2448 GNUNET_free (hd->domain);
2449 MHD_stop_daemon (hd->daemon);
2450 if (NULL != hd->httpd_task)
2451 {
2453 hd->httpd_task = NULL;
2454 }
2455 GNUNET_free (hd->proxy_cert);
2456 if (hd == httpd)
2457 httpd = NULL;
2458 GNUNET_free (hd);
2459}
2460
2461
2467static void
2468kill_httpd_task (void *cls)
2469{
2470 struct MhdHttpList *hd = cls;
2471
2472 hd->httpd_task = NULL;
2473 kill_httpd (hd);
2474}
2475
2476
2482static void
2483do_httpd (void *cls);
2484
2485
2493static void
2494schedule_httpd (struct MhdHttpList *hd)
2495{
2496 fd_set rs;
2497 fd_set ws;
2498 fd_set es;
2499 struct GNUNET_NETWORK_FDSet *wrs;
2500 struct GNUNET_NETWORK_FDSet *wws;
2501 int max;
2502 int haveto;
2503 MHD_UNSIGNED_LONG_LONG timeout;
2504 struct GNUNET_TIME_Relative tv;
2505
2506 FD_ZERO (&rs);
2507 FD_ZERO (&ws);
2508 FD_ZERO (&es);
2509 max = -1;
2510 if (MHD_YES !=
2511 MHD_get_fdset (hd->daemon,
2512 &rs,
2513 &ws,
2514 &es,
2515 &max))
2516 {
2517 kill_httpd (hd);
2518 return;
2519 }
2520 haveto = MHD_get_timeout (hd->daemon,
2521 &timeout);
2522 if (MHD_YES == haveto)
2523 tv.rel_value_us = (uint64_t) timeout * 1000LL;
2524 else
2526 if (-1 != max)
2527 {
2530 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
2531 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
2532 }
2533 else
2534 {
2535 wrs = NULL;
2536 wws = NULL;
2537 }
2538 if (NULL != hd->httpd_task)
2539 {
2541 hd->httpd_task = NULL;
2542 }
2543 if ((MHD_YES != haveto) &&
2544 (-1 == max) &&
2545 (hd != httpd))
2546 {
2547 /* daemon is idle, kill after timeout */
2550 hd);
2551 }
2552 else
2553 {
2554 hd->httpd_task =
2556 tv, wrs, wws,
2557 &do_httpd, hd);
2558 }
2559 if (NULL != wrs)
2561 if (NULL != wws)
2563}
2564
2565
2566static void
2567do_httpd (void *cls)
2568{
2569 struct MhdHttpList *hd = cls;
2570
2571 hd->httpd_task = NULL;
2572 MHD_run (hd->daemon);
2573 schedule_httpd (hd);
2574}
2575
2576
2582static void
2583run_mhd_now (struct MhdHttpList *hd)
2584{
2585 if (NULL != hd->httpd_task)
2588 hd);
2589}
2590
2591
2599static void*
2600load_file (const char*filename,
2601 unsigned int*size)
2602{
2603 void *buffer;
2604 uint64_t fsize;
2605
2606 if (GNUNET_OK !=
2608 &fsize,
2609 GNUNET_YES,
2610 GNUNET_YES))
2611 return NULL;
2612 if (fsize > MAX_PEM_SIZE)
2613 return NULL;
2614 *size = (unsigned int) fsize;
2615 buffer = GNUNET_malloc (*size);
2616 if (fsize !=
2618 buffer,
2619 (size_t) fsize))
2620 {
2621 GNUNET_free (buffer);
2622 return NULL;
2623 }
2624 return buffer;
2625}
2626
2627
2635static int
2636load_key_from_file (gnutls_x509_privkey_t key,
2637 const char*keyfile)
2638{
2639 gnutls_datum_t key_data;
2640 int ret;
2641
2642 key_data.data = load_file (keyfile,
2643 &key_data.size);
2644 if (NULL == key_data.data)
2645 return GNUNET_SYSERR;
2646 ret = gnutls_x509_privkey_import (key, &key_data,
2647 GNUTLS_X509_FMT_PEM);
2648 if (GNUTLS_E_SUCCESS != ret)
2649 {
2651 _ ("Unable to import private key from file `%s'\n"),
2652 keyfile);
2653 }
2654 GNUNET_free (key_data.data);
2655 return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2656}
2657
2658
2666static int
2667load_cert_from_file (gnutls_x509_crt_t crt,
2668 const char*certfile)
2669{
2670 gnutls_datum_t cert_data;
2671 int ret;
2672
2673 cert_data.data = load_file (certfile,
2674 &cert_data.size);
2675 if (NULL == cert_data.data)
2676 return GNUNET_SYSERR;
2677 ret = gnutls_x509_crt_import (crt,
2678 &cert_data,
2679 GNUTLS_X509_FMT_PEM);
2680 if (GNUTLS_E_SUCCESS != ret)
2681 {
2683 _ ("Unable to import certificate from `%s'\n"),
2684 certfile);
2685 }
2686 GNUNET_free (cert_data.data);
2687 return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2688}
2689
2690
2697static struct ProxyGNSCertificate *
2698generate_gns_certificate (const char *name)
2699{
2700 unsigned int serial;
2701 size_t key_buf_size;
2702 size_t cert_buf_size;
2703 gnutls_x509_crt_t request;
2704 time_t etime;
2705 struct tm *tm_data;
2706 struct ProxyGNSCertificate *pgc;
2707
2709 "Generating x.509 certificate for `%s'\n",
2710 name);
2711 GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_init (&request));
2712 GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_set_key (request,
2713 proxy_ca.key));
2714 pgc = GNUNET_new (struct ProxyGNSCertificate);
2715 gnutls_x509_crt_set_dn_by_oid (request,
2716 GNUTLS_OID_X520_COUNTRY_NAME,
2717 0,
2718 "ZZ",
2719 strlen ("ZZ"));
2720 gnutls_x509_crt_set_dn_by_oid (request,
2721 GNUTLS_OID_X520_ORGANIZATION_NAME,
2722 0,
2723 "GNU Name System",
2724 strlen ("GNU Name System"));
2725 gnutls_x509_crt_set_dn_by_oid (request,
2726 GNUTLS_OID_X520_COMMON_NAME,
2727 0,
2728 name,
2729 strlen (name));
2730 gnutls_x509_crt_set_subject_alternative_name (request,
2731 GNUTLS_SAN_DNSNAME,
2732 name);
2733 GNUNET_break (GNUTLS_E_SUCCESS ==
2734 gnutls_x509_crt_set_version (request,
2735 3));
2736 gnutls_rnd (GNUTLS_RND_NONCE,
2737 &serial,
2738 sizeof(serial));
2739 gnutls_x509_crt_set_serial (request,
2740 &serial,
2741 sizeof(serial));
2742 etime = time (NULL);
2743 tm_data = localtime (&etime);
2744 tm_data->tm_hour--;
2745 etime = mktime (tm_data);
2746 gnutls_x509_crt_set_activation_time (request,
2747 etime);
2748 tm_data->tm_year++;
2749 etime = mktime (tm_data);
2750 gnutls_x509_crt_set_expiration_time (request,
2751 etime);
2752 gnutls_x509_crt_sign2 (request,
2753 proxy_ca.cert,
2754 proxy_ca.key,
2755 GNUTLS_DIG_SHA512,
2756 0);
2757 key_buf_size = sizeof(pgc->key);
2758 cert_buf_size = sizeof(pgc->cert);
2759 gnutls_x509_crt_export (request,
2760 GNUTLS_X509_FMT_PEM,
2761 pgc->cert,
2762 &cert_buf_size);
2763 gnutls_x509_privkey_export (proxy_ca.key,
2764 GNUTLS_X509_FMT_PEM,
2765 pgc->key,
2766 &key_buf_size);
2767 gnutls_x509_crt_deinit (request);
2768 return pgc;
2769}
2770
2771
2779static void
2780mhd_error_log_callback (void *cls,
2781 const char *fm,
2782 va_list ap)
2783{
2784 /* do nothing */
2785}
2786
2787
2794static struct MhdHttpList *
2795lookup_ssl_httpd (const char*domain)
2796{
2797 struct MhdHttpList *hd;
2798 struct ProxyGNSCertificate *pgc;
2799
2800 if (NULL == domain)
2801 {
2802 GNUNET_break (0);
2803 return NULL;
2804 }
2805 for (hd = mhd_httpd_head; NULL != hd; hd = hd->next)
2806 if ((NULL != hd->domain) &&
2807 (0 == strcmp (hd->domain, domain)))
2808 return hd;
2810 "Starting fresh MHD HTTPS instance for domain `%s'\n",
2811 domain);
2812 pgc = generate_gns_certificate (domain);
2813 hd = GNUNET_new (struct MhdHttpList);
2814 hd->is_ssl = GNUNET_YES;
2815 hd->domain = GNUNET_strdup (domain);
2816 hd->proxy_cert = pgc;
2817 hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL
2818 | MHD_USE_NO_LISTEN_SOCKET
2819 | MHD_ALLOW_SUSPEND_RESUME,
2820 0,
2821 NULL, NULL,
2822 &create_response, hd,
2823 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
2824 int) 16,
2825 MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
2826 NULL,
2827 MHD_OPTION_NOTIFY_CONNECTION,
2828 &mhd_connection_cb, NULL,
2829 MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
2830 NULL,
2831 MHD_OPTION_EXTERNAL_LOGGER,
2833 MHD_OPTION_HTTPS_MEM_KEY, pgc->key,
2834 MHD_OPTION_HTTPS_MEM_CERT, pgc->cert,
2835 MHD_OPTION_END);
2836 if (NULL == hd->daemon)
2837 {
2838 GNUNET_free (pgc);
2839 GNUNET_free (hd);
2840 return NULL;
2841 }
2844 hd);
2845 return hd;
2846}
2847
2848
2856static void
2857timeout_s5r_handshake (void *cls)
2858{
2859 struct Socks5Request *s5r = cls;
2860
2861 s5r->timeout_task = NULL;
2862 cleanup_s5r (s5r);
2863}
2864
2865
2874static void
2876{
2877 struct MhdHttpList *hd;
2878 int fd;
2879 const struct sockaddr *addr;
2880 socklen_t len;
2881 char *domain;
2882
2883 if (GNUNET_YES == s5r->is_tls)
2884 {
2885 GNUNET_asprintf (&domain,
2886 "%s",
2887 s5r->domain);
2888 hd = lookup_ssl_httpd (domain);
2889 if (NULL == hd)
2890 {
2892 _ ("Failed to start HTTPS server for `%s'\n"),
2893 s5r->domain);
2894 cleanup_s5r (s5r);
2895 GNUNET_free (domain);
2896 return;
2897 }
2898 }
2899 else
2900 {
2901 domain = NULL;
2902 GNUNET_assert (NULL != httpd);
2903 hd = httpd;
2904 }
2905 fd = GNUNET_NETWORK_get_fd (s5r->sock);
2906 addr = GNUNET_NETWORK_get_addr (s5r->sock);
2907 len = GNUNET_NETWORK_get_addrlen (s5r->sock);
2909 if (MHD_YES !=
2910 MHD_add_connection (hd->daemon,
2911 fd,
2912 addr,
2913 len))
2914 {
2916 _ ("Failed to pass client to MHD\n"));
2917 cleanup_s5r (s5r);
2918 GNUNET_free (domain);
2919 return;
2920 }
2921 s5r->hd = hd;
2922 schedule_httpd (hd);
2925 s5r);
2926 GNUNET_free (domain);
2927}
2928
2929
2930/* ********************* SOCKS handling ************************* */
2931
2932
2938static void
2939do_write (void *cls)
2940{
2941 struct Socks5Request *s5r = cls;
2942 ssize_t len;
2943
2944 s5r->wtask = NULL;
2945 len = GNUNET_NETWORK_socket_send (s5r->sock,
2946 s5r->wbuf,
2947 s5r->wbuf_len);
2948 if (len <= 0)
2949 {
2950 /* write error: connection closed, shutdown, etc.; just clean up */
2952 "Write Error\n");
2953 cleanup_s5r (s5r);
2954 return;
2955 }
2956 memmove (s5r->wbuf,
2957 &s5r->wbuf[len],
2958 s5r->wbuf_len - len);
2959 s5r->wbuf_len -= len;
2960 if (s5r->wbuf_len > 0)
2961 {
2962 /* not done writing */
2963 s5r->wtask =
2965 s5r->sock,
2966 &do_write, s5r);
2967 return;
2968 }
2969
2970 /* we're done writing, continue with state machine! */
2971
2972 switch (s5r->state)
2973 {
2974 case SOCKS5_INIT:
2975 GNUNET_assert (0);
2976 break;
2977
2978 case SOCKS5_REQUEST:
2979 GNUNET_assert (NULL != s5r->rtask);
2980 break;
2981
2983 setup_data_transfer (s5r);
2984 return;
2985
2987 cleanup_s5r (s5r);
2988 return;
2989
2990 default:
2991 GNUNET_break (0);
2992 break;
2993 }
2994}
2995
2996
3003static void
3005 enum Socks5StatusCode sc)
3006{
3007 struct Socks5ServerResponseMessage *s_resp;
3008
3009 GNUNET_break (0 == s5r->wbuf_len); /* Should happen first in any transmission, right? */
3011 sizeof(struct Socks5ServerResponseMessage));
3012 s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3013 memset (s_resp, 0, sizeof(struct Socks5ServerResponseMessage));
3014 s_resp->version = SOCKS_VERSION_5;
3015 s_resp->reply = sc;
3017 if (NULL != s5r->wtask)
3018 s5r->wtask =
3020 s5r->sock,
3021 &do_write, s5r);
3022}
3023
3024
3030static void
3032{
3033 struct Socks5ServerResponseMessage *s_resp;
3034
3035 s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3036 s_resp->version = SOCKS_VERSION_5;
3037 s_resp->reply = SOCKS5_STATUS_REQUEST_GRANTED;
3038 s_resp->reserved = 0;
3039 s_resp->addr_type = SOCKS5_AT_IPV4;
3040 /* zero out IPv4 address and port */
3041 memset (&s_resp[1],
3042 0,
3043 sizeof(struct in_addr) + sizeof(uint16_t));
3044 s5r->wbuf_len += sizeof(struct Socks5ServerResponseMessage)
3045 + sizeof(struct in_addr) + sizeof(uint16_t);
3046 if (NULL == s5r->wtask)
3047 s5r->wtask =
3049 s5r->sock,
3050 &do_write, s5r);
3051}
3052
3053
3062static void
3063handle_gns_result (void *cls,
3064 int tld,
3065 uint32_t rd_count,
3066 const struct GNUNET_GNSRECORD_Data *rd)
3067{
3068 struct Socks5Request *s5r = cls;
3069 const struct GNUNET_GNSRECORD_Data *r;
3070 int got_ip;
3071
3072 s5r->gns_lookup = NULL;
3073 s5r->is_gns = tld;
3074 got_ip = GNUNET_NO;
3075 for (uint32_t i = 0; i < rd_count; i++)
3076 {
3077 r = &rd[i];
3078 switch (r->record_type)
3079 {
3081 {
3082 struct sockaddr_in *in;
3083
3084 if (sizeof(struct in_addr) != r->data_size)
3085 {
3086 GNUNET_break_op (0);
3087 break;
3088 }
3089 if (GNUNET_YES == got_ip)
3090 break;
3091 if (GNUNET_OK !=
3092 GNUNET_NETWORK_test_pf (PF_INET))
3093 break;
3094 got_ip = GNUNET_YES;
3095 in = (struct sockaddr_in *) &s5r->destination_address;
3096 in->sin_family = AF_INET;
3097 GNUNET_memcpy (&in->sin_addr,
3098 r->data,
3099 r->data_size);
3100 in->sin_port = htons (s5r->port);
3101#if HAVE_SOCKADDR_IN_SIN_LEN
3102 in->sin_len = sizeof(*in);
3103#endif
3104 }
3105 break;
3106
3108 {
3109 struct sockaddr_in6 *in;
3110
3111 if (sizeof(struct in6_addr) != r->data_size)
3112 {
3113 GNUNET_break_op (0);
3114 break;
3115 }
3116 if (GNUNET_YES == got_ip)
3117 break;
3118 if (GNUNET_YES == disable_v6)
3119 break;
3120 if (GNUNET_OK !=
3121 GNUNET_NETWORK_test_pf (PF_INET6))
3122 break;
3123 /* FIXME: allow user to disable IPv6 per configuration option... */
3124 got_ip = GNUNET_YES;
3125 in = (struct sockaddr_in6 *) &s5r->destination_address;
3126 in->sin6_family = AF_INET6;
3127 GNUNET_memcpy (&in->sin6_addr,
3128 r->data,
3129 r->data_size);
3130 in->sin6_port = htons (s5r->port);
3131#if HAVE_SOCKADDR_IN_SIN_LEN
3132 in->sin6_len = sizeof(*in);
3133#endif
3134 }
3135 break;
3136
3138 GNUNET_break (0); /* should have been translated within GNS */
3139 break;
3140
3142 GNUNET_free (s5r->leho);
3143 s5r->leho = GNUNET_strndup (r->data,
3144 r->data_size);
3145 break;
3146
3148 {
3149 const struct GNUNET_GNSRECORD_BoxRecord *box;
3150
3151 if (r->data_size < sizeof(struct GNUNET_GNSRECORD_BoxRecord))
3152 {
3153 GNUNET_break_op (0);
3154 break;
3155 }
3156 box = r->data;
3157 if ((ntohl (box->record_type) != GNUNET_DNSPARSER_TYPE_TLSA) ||
3158 (ntohs (box->protocol) != IPPROTO_TCP) ||
3159 (ntohs (box->service) != s5r->port))
3160 break; /* BOX record does not apply */
3161 if (s5r->num_danes >= MAX_DANES)
3162 {
3163 GNUNET_break (0); /* MAX_DANES too small */
3164 break;
3165 }
3166 s5r->is_tls = GNUNET_YES; /* This should be TLS */
3167 s5r->dane_data_len[s5r->num_danes]
3168 = r->data_size - sizeof(struct GNUNET_GNSRECORD_BoxRecord);
3169 s5r->dane_data[s5r->num_danes]
3170 = GNUNET_memdup (&box[1],
3171 s5r->dane_data_len[s5r->num_danes]);
3172 s5r->num_danes++;
3173 break;
3174 }
3175
3176 default:
3177 /* don't care */
3178 break;
3179 }
3180 }
3181 if ((GNUNET_YES != got_ip) &&
3182 (GNUNET_YES == tld))
3183 {
3185 "Name resolution failed to yield useful IP address.\n");
3188 return;
3189 }
3192}
3193
3194
3201static void
3203 size_t len)
3204{
3205 GNUNET_assert (len <= s5r->rbuf_len);
3206 memmove (s5r->rbuf,
3207 &s5r->rbuf[len],
3208 s5r->rbuf_len - len);
3209 s5r->rbuf_len -= len;
3210}
3211
3212
3218static void
3219do_s5r_read (void *cls)
3220{
3221 struct Socks5Request *s5r = cls;
3222 const struct Socks5ClientHelloMessage *c_hello;
3223 struct Socks5ServerHelloMessage *s_hello;
3224 const struct Socks5ClientRequestMessage *c_req;
3225 ssize_t rlen;
3226 size_t alen;
3227 const struct GNUNET_SCHEDULER_TaskContext *tc;
3228
3229 s5r->rtask = NULL;
3231 if ((NULL != tc->read_ready) &&
3233 s5r->sock)))
3234 {
3235 rlen = GNUNET_NETWORK_socket_recv (s5r->sock,
3236 &s5r->rbuf[s5r->rbuf_len],
3237 sizeof(s5r->rbuf) - s5r->rbuf_len);
3238 if (rlen <= 0)
3239 {
3241 "socks5 client disconnected.\n");
3242 cleanup_s5r (s5r);
3243 return;
3244 }
3245 s5r->rbuf_len += rlen;
3246 }
3248 s5r->sock,
3249 &do_s5r_read, s5r);
3251 "Processing %zu bytes of socks data in state %d\n",
3252 s5r->rbuf_len,
3253 s5r->state);
3254 switch (s5r->state)
3255 {
3256 case SOCKS5_INIT:
3257 c_hello = (const struct Socks5ClientHelloMessage*) &s5r->rbuf;
3258 if ((s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)) ||
3259 (s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)
3260 + c_hello->num_auth_methods))
3261 return; /* need more data */
3262 if (SOCKS_VERSION_5 != c_hello->version)
3263 {
3265 _ ("Unsupported socks version %d\n"),
3266 (int) c_hello->version);
3267 cleanup_s5r (s5r);
3268 return;
3269 }
3271 sizeof(struct Socks5ClientHelloMessage)
3272 + c_hello->num_auth_methods);
3273 GNUNET_assert (0 == s5r->wbuf_len);
3274 s_hello = (struct Socks5ServerHelloMessage *) &s5r->wbuf;
3275 s5r->wbuf_len = sizeof(struct Socks5ServerHelloMessage);
3276 s_hello->version = SOCKS_VERSION_5;
3277 s_hello->auth_method = SOCKS_AUTH_NONE;
3278 GNUNET_assert (NULL == s5r->wtask);
3280 s5r->sock,
3281 &do_write, s5r);
3282 s5r->state = SOCKS5_REQUEST;
3283 return;
3284
3285 case SOCKS5_REQUEST:
3286 c_req = (const struct Socks5ClientRequestMessage *) &s5r->rbuf;
3287 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage))
3288 return;
3289 switch (c_req->command)
3290 {
3292 /* handled below */
3293 break;
3294
3295 default:
3297 _ ("Unsupported socks command %d\n"),
3298 (int) c_req->command);
3301 return;
3302 }
3303 switch (c_req->addr_type)
3304 {
3305 case SOCKS5_AT_IPV4:
3306 {
3307 const struct in_addr *v4 = (const struct in_addr *) &c_req[1];
3308 const uint16_t *v4port = (const uint16_t *) &v4[1];
3309 struct sockaddr_in *in;
3310
3311 s5r->port = ntohs (*v4port);
3312 alen = sizeof(struct in_addr);
3313 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3314 + alen + sizeof(uint16_t))
3315 return; /* need more data */
3316 in = (struct sockaddr_in *) &s5r->destination_address;
3317 in->sin_family = AF_INET;
3318 in->sin_addr = *v4;
3319 in->sin_port = *v4port;
3320#if HAVE_SOCKADDR_IN_SIN_LEN
3321 in->sin_len = sizeof(*in);
3322#endif
3324 }
3325 break;
3326
3327 case SOCKS5_AT_IPV6:
3328 {
3329 const struct in6_addr *v6 = (const struct in6_addr *) &c_req[1];
3330 const uint16_t *v6port = (const uint16_t *) &v6[1];
3331 struct sockaddr_in6 *in;
3332
3333 s5r->port = ntohs (*v6port);
3334 alen = sizeof(struct in6_addr);
3335 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3336 + alen + sizeof(uint16_t))
3337 return; /* need more data */
3338 in = (struct sockaddr_in6 *) &s5r->destination_address;
3339 in->sin6_family = AF_INET6;
3340 in->sin6_addr = *v6;
3341 in->sin6_port = *v6port;
3342#if HAVE_SOCKADDR_IN_SIN_LEN
3343 in->sin6_len = sizeof(*in);
3344#endif
3346 }
3347 break;
3348
3350 {
3351 const uint8_t *dom_len;
3352 const char *dom_name;
3353 const uint16_t *dport;
3354
3355 dom_len = (const uint8_t *) &c_req[1];
3356 alen = *dom_len + 1;
3357 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3358 + alen + sizeof(uint16_t))
3359 return; /* need more data */
3360 dom_name = (const char *) &dom_len[1];
3361 dport = (const uint16_t *) &dom_name[*dom_len];
3362 s5r->domain = GNUNET_strndup (dom_name,
3363 *dom_len);
3365 "Requested connection is to %s:%d\n",
3366 // (HTTPS_PORT == s5r->port) ? "s" : "",
3367 s5r->domain,
3368 ntohs (*dport));
3369 s5r->state = SOCKS5_RESOLVING;
3370 s5r->port = ntohs (*dport);
3371 s5r->is_tls = (HTTPS_PORT == s5r->port) ? GNUNET_YES : GNUNET_NO;
3373 s5r->domain,
3375 GNUNET_GNS_LO_LOCAL_MASTER /* only cached */
3376 ,
3378 s5r);
3379 break;
3380 }
3381
3382 default:
3384 _ ("Unsupported socks address type %d\n"),
3385 (int) c_req->addr_type);
3388 return;
3389 }
3391 sizeof(struct Socks5ClientRequestMessage)
3392 + alen + sizeof(uint16_t));
3393 if (0 != s5r->rbuf_len)
3394 {
3395 /* read more bytes than healthy, why did the client send more!? */
3396 GNUNET_break_op (0);
3399 return;
3400 }
3401 if (SOCKS5_DATA_TRANSFER == s5r->state)
3402 {
3403 /* if we are not waiting for GNS resolution, signal success */
3405 }
3406 /* We are done reading right now */
3408 s5r->rtask = NULL;
3409 return;
3410
3411 case SOCKS5_RESOLVING:
3412 GNUNET_assert (0);
3413 return;
3414
3416 GNUNET_assert (0);
3417 return;
3418
3419 default:
3420 GNUNET_assert (0);
3421 return;
3422 }
3423}
3424
3425
3431static void
3432do_accept (void *cls)
3433{
3434 struct GNUNET_NETWORK_Handle *lsock = cls;
3435 struct GNUNET_NETWORK_Handle *s;
3436 struct Socks5Request *s5r;
3437
3438 GNUNET_assert (NULL != lsock);
3439 if (lsock == lsock4)
3441 lsock,
3442 &do_accept,
3443 lsock);
3444 else if (lsock == lsock6)
3446 lsock,
3447 &do_accept,
3448 lsock);
3449 else
3450 GNUNET_assert (0);
3452 NULL,
3453 NULL);
3454 if (NULL == s)
3455 {
3457 "accept");
3458 return;
3459 }
3461 "Got an inbound connection, waiting for data\n");
3462 s5r = GNUNET_new (struct Socks5Request);
3464 s5r_tail,
3465 s5r);
3466 s5r->sock = s;
3467 s5r->state = SOCKS5_INIT;
3469 s5r->sock,
3470 &do_s5r_read,
3471 s5r);
3472}
3473
3474
3475/* ******************* General / main code ********************* */
3476
3477
3483static void
3484do_shutdown (void *cls)
3485{
3487 "Shutting down...\n");
3488 /* MHD requires resuming before destroying the daemons */
3489 for (struct Socks5Request *s5r = s5r_head;
3490 NULL != s5r;
3491 s5r = s5r->next)
3492 {
3493 if (s5r->suspended)
3494 {
3495 s5r->suspended = GNUNET_NO;
3496 MHD_resume_connection (s5r->con);
3497 }
3498 }
3499 while (NULL != mhd_httpd_head)
3501 while (NULL != s5r_head)
3503 if (NULL != lsock4)
3504 {
3506 lsock4 = NULL;
3507 }
3508 if (NULL != lsock6)
3509 {
3511 lsock6 = NULL;
3512 }
3513 if (NULL != curl_multi)
3514 {
3515 curl_multi_cleanup (curl_multi);
3516 curl_multi = NULL;
3517 }
3518 if (NULL != gns_handle)
3519 {
3521 gns_handle = NULL;
3522 }
3523 if (NULL != curl_download_task)
3524 {
3526 curl_download_task = NULL;
3527 }
3528 if (NULL != ltask4)
3529 {
3531 ltask4 = NULL;
3532 }
3533 if (NULL != ltask6)
3534 {
3536 ltask6 = NULL;
3537 }
3538 gnutls_x509_crt_deinit (proxy_ca.cert);
3539 gnutls_x509_privkey_deinit (proxy_ca.key);
3540 gnutls_global_deinit ();
3541}
3542
3543
3549static struct GNUNET_NETWORK_Handle *
3550bind_v4 ()
3551{
3552 struct GNUNET_NETWORK_Handle *ls;
3553 struct sockaddr_in sa4;
3554 int eno;
3555
3556 memset (&sa4, 0, sizeof(sa4));
3557 sa4.sin_family = AF_INET;
3558 sa4.sin_port = htons (port);
3559 sa4.sin_addr.s_addr = address;
3560#if HAVE_SOCKADDR_IN_SIN_LEN
3561 sa4.sin_len = sizeof(sa4);
3562#endif
3564 SOCK_STREAM,
3565 0);
3566 if (NULL == ls)
3567 return NULL;
3568 if (GNUNET_OK !=
3570 (const struct sockaddr *) &sa4,
3571 sizeof(sa4)))
3572 {
3573 eno = errno;
3575 errno = eno;
3576 return NULL;
3577 }
3578 return ls;
3579}
3580
3581
3587static struct GNUNET_NETWORK_Handle *
3588bind_v6 ()
3589{
3590 struct GNUNET_NETWORK_Handle *ls;
3591 struct sockaddr_in6 sa6;
3592 int eno;
3593
3594 memset (&sa6, 0, sizeof(sa6));
3595 sa6.sin6_family = AF_INET6;
3596 sa6.sin6_port = htons (port);
3597 sa6.sin6_addr = address6;
3598#if HAVE_SOCKADDR_IN_SIN_LEN
3599 sa6.sin6_len = sizeof(sa6);
3600#endif
3601 ls = GNUNET_NETWORK_socket_create (AF_INET6,
3602 SOCK_STREAM,
3603 0);
3604 if (NULL == ls)
3605 return NULL;
3606 if (GNUNET_OK !=
3608 (const struct sockaddr *) &sa6,
3609 sizeof(sa6)))
3610 {
3611 eno = errno;
3613 errno = eno;
3614 return NULL;
3615 }
3616 return ls;
3617}
3618
3619
3628static void
3629run (void *cls,
3630 char *const *args,
3631 const char *cfgfile,
3632 const struct GNUNET_CONFIGURATION_Handle *c)
3633{
3634 char*cafile_cfg = NULL;
3635 char*cafile;
3636 char*addr_str;
3637 struct MhdHttpList *hd;
3638
3639 cfg = c;
3640
3641 /* Get address to bind to */
3643 "BIND_TO",
3644 &addr_str))
3645 {
3646 // No address specified
3648 "Don't know what to bind to...\n");
3649 GNUNET_free (addr_str);
3651 return;
3652 }
3653 if (1 != inet_pton (AF_INET, addr_str, &address))
3654 {
3656 "Unable to parse address %s\n",
3657 addr_str);
3658 GNUNET_free (addr_str);
3660 return;
3661 }
3662 GNUNET_free (addr_str);
3663 /* Get address to bind to */
3665 "BIND_TO6",
3666 &addr_str))
3667 {
3668 // No address specified
3670 "Don't know what to bind6 to...\n");
3671 GNUNET_free (addr_str);
3673 return;
3674 }
3675 if (1 != inet_pton (AF_INET6, addr_str, &address6))
3676 {
3678 "Unable to parse IPv6 address %s\n",
3679 addr_str);
3680 GNUNET_free (addr_str);
3682 return;
3683 }
3684 GNUNET_free (addr_str);
3685
3686 if (NULL == (curl_multi = curl_multi_init ()))
3687 {
3689 "Failed to create cURL multi handle!\n");
3690 return;
3691 }
3692 cafile = cafile_opt;
3693 if (NULL == cafile)
3694 {
3695 if (GNUNET_OK !=
3697 "gns-proxy",
3698 "PROXY_CACERT",
3699 &cafile_cfg))
3700 {
3702 "gns-proxy",
3703 "PROXY_CACERT");
3704 return;
3705 }
3706 cafile = cafile_cfg;
3707 }
3709 "Using `%s' as CA\n",
3710 cafile);
3711
3712 gnutls_global_init ();
3713 gnutls_x509_crt_init (&proxy_ca.cert);
3714 gnutls_x509_privkey_init (&proxy_ca.key);
3715
3716 if ((GNUNET_OK !=
3718 cafile)) ||
3719 (GNUNET_OK !=
3721 cafile)))
3722 {
3724 _ ("Failed to load X.509 key and certificate from `%s'\n"),
3725 cafile);
3726 gnutls_x509_crt_deinit (proxy_ca.cert);
3727 gnutls_x509_privkey_deinit (proxy_ca.key);
3728 gnutls_global_deinit ();
3729 GNUNET_free (cafile_cfg);
3730 return;
3731 }
3732 GNUNET_free (cafile_cfg);
3733 if (NULL == (gns_handle = GNUNET_GNS_connect (cfg)))
3734 {
3736 "Unable to connect to GNS!\n");
3737 gnutls_x509_crt_deinit (proxy_ca.cert);
3738 gnutls_x509_privkey_deinit (proxy_ca.key);
3739 gnutls_global_deinit ();
3740 return;
3741 }
3743 NULL);
3744
3745 /* Open listen socket for socks proxy */
3746 lsock6 = bind_v6 ();
3747 if (NULL == lsock6)
3748 {
3750 "bind");
3751 }
3752 else
3753 {
3754 if (GNUNET_OK !=
3756 5))
3757 {
3759 "listen");
3761 lsock6 = NULL;
3762 }
3763 else
3764 {
3766 lsock6,
3767 &do_accept,
3768 lsock6);
3769 }
3770 }
3771 lsock4 = bind_v4 ();
3772 if (NULL == lsock4)
3773 {
3775 "bind");
3776 }
3777 else
3778 {
3779 if (GNUNET_OK !=
3781 5))
3782 {
3784 "listen");
3786 lsock4 = NULL;
3787 }
3788 else
3789 {
3791 lsock4,
3792 &do_accept,
3793 lsock4);
3794 }
3795 }
3796 if ((NULL == lsock4) &&
3797 (NULL == lsock6))
3798 {
3800 return;
3801 }
3802 if (CURLSSLSET_OK != curl_global_sslset (CURLSSLBACKEND_GNUTLS,
3803 NULL,
3804 NULL))
3805 {
3807 "cURL does not support the GnuTLS backend\n");
3808
3809 }
3810 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
3811 {
3813 "cURL global init failed!\n");
3815 return;
3816 }
3818 "Proxy listens on port %u\n",
3819 (unsigned int) port);
3820
3821 /* start MHD daemon for HTTP */
3822 hd = GNUNET_new (struct MhdHttpList);
3823 hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
3824 | MHD_ALLOW_SUSPEND_RESUME,
3825 0,
3826 NULL, NULL,
3827 &create_response, hd,
3828 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
3829 int) 16,
3830 MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
3831 NULL,
3832 MHD_OPTION_NOTIFY_CONNECTION,
3833 &mhd_connection_cb, NULL,
3834 MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
3835 NULL,
3836 MHD_OPTION_END);
3837 if (NULL == hd->daemon)
3838 {
3839 GNUNET_free (hd);
3841 return;
3842 }
3843 httpd = hd;
3846 hd);
3847}
3848
3849
3857int
3858main (int argc,
3859 char *const *argv)
3860{
3863 "port",
3864 NULL,
3865 gettext_noop (
3866 "listen on specified port (default: 7777)"),
3867 &port),
3869 "authority",
3870 NULL,
3871 gettext_noop ("pem file to use as CA"),
3872 &cafile_opt),
3874 "disable-ivp6",
3875 gettext_noop ("disable use of IPv6"),
3876 &disable_v6),
3877
3879 };
3880 static const char*page =
3881 "<html><head><title>gnunet-gns-proxy</title>"
3882 "</head><body>cURL fail</body></html>";
3883 int ret;
3884
3885 GNUNET_log_setup ("gnunet-gns-proxy",
3886 "WARNING",
3887 NULL);
3889 = MHD_create_response_from_buffer (strlen (page),
3890 (void *) page,
3891 MHD_RESPMEM_PERSISTENT);
3892
3893 ret =
3894 (GNUNET_OK ==
3896 argc, argv,
3897 "gnunet-gns-proxy",
3898 _ ("GNUnet GNS proxy"),
3899 options,
3900 &run, NULL)) ? 0 : 1;
3901 MHD_destroy_response (curl_failure_response);
3902 return ret;
3903}
3904
3905
3906/* end of gnunet-gns-proxy.c */
struct GNUNET_GETOPT_CommandLineOption options[]
Definition 002.c:5
struct GNUNET_MessageHeader * msg
Definition 005.c:2
static mp_limb_t d[(((256)+GMP_NUMB_BITS - 1)/GMP_NUMB_BITS)]
int main()
Program to simulate results from GCP_get_desirability_of_path() for various plausible inputs.
#define gettext_noop(String)
Definition gettext.h:74
#define GNUNET_GNSRECORD_TYPE_BOX
Box record.
#define GNUNET_GNSRECORD_TYPE_VPN
VPN resolution.
#define GNUNET_GNSRECORD_TYPE_LEHO
GNS legacy hostname.
static int verify
Verify mode.
Definition gnunet-abd.c:128
static int start
Set if we are to start default services (including ARM).
Definition gnunet-arm.c:38
static int ret
Final status code.
Definition gnunet-arm.c:93
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition gnunet-arm.c:118
static int do_shutdown
Set to GNUNET_YES if we are shutting down.
static struct GNUNET_TESTING_Interpreter * is
static char * data
The data to insert into the dht.
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_FS_Handle * ctx
static char * filename
static struct MhdHttpList * mhd_httpd_tail
DLL for http/https daemons.
static void do_s5r_read(void *cls)
Read data from incoming Socks5 connection.
static struct ProxyCA proxy_ca
The CA for X.509 certificate generation.
static struct Socks5Request * s5r_tail
DLL of active socks requests.
static void * load_file(const char *filename, unsigned int *size)
Read file in filename.
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 size_t curl_download_cb(void *ptr, size_t size, size_t nmemb, void *ctx)
Handle response payload data from cURL.
static struct GNUNET_GNS_Handle * gns_handle
Handle to the GNS service.
static void signal_socks_success(struct Socks5Request *s5r)
Return a server response message indicating success.
#define SOCKS_AUTH_NONE
Flag to set for 'no authentication'.
static struct GNUNET_NETWORK_Handle * bind_v4()
Create an IPv4 listen socket bound to our port.
static CURLM * curl_multi
The cURL multi handle.
@ SOCKS5_CMD_TCP_STREAM
Establish TCP/IP stream.
#define MAX_PEM_SIZE
Largest allowed size for a PEM certificate.
static struct GNUNET_NETWORK_Handle * bind_v6()
Create an IPv6 listen socket bound to our port.
static int disable_v6
Disable IPv6.
static char * cafile_opt
The CA file (pem) to use for the proxy CA.
static struct GNUNET_NETWORK_Handle * lsock6
The listen socket of the proxy for IPv6.
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
@ 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.
#define SOCKS_VERSION_5
Which SOCKS version do we speak?
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 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 struct GNUNET_NETWORK_Handle * lsock4
The listen socket of the proxy for IPv4.
static void clear_from_s5r_rbuf(struct Socks5Request *s5r, size_t len)
Remove the first len bytes from the beginning of the read buffer.
static void curl_download_prepare(void)
Ask cURL for the select() sets and schedule cURL operations.
static struct in6_addr address6
The IPv6 address to bind to.
static int load_key_from_file(gnutls_x509_privkey_t key, const char *keyfile)
Load PEM key from file.
#define HTTPS_PORT
Port for HTTPS.
static void mhd_error_log_callback(void *cls, const char *fm, va_list ap)
Function called by MHD with errors, suppresses them all.
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 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.
#define SOCKS_BUFFERSIZE
Size of the read/write buffers for Socks.
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
Main function that will be run.
static uint16_t port
The port the proxy is running on (default 7777)
static void do_httpd(void *cls)
Task run whenever HTTP server operations are pending.
static struct MhdHttpList * httpd
Daemon for HTTP (we have one per X.509 certificate, and then one for all HTTP connections; this is th...
@ SOCKS5_AT_DOMAINNAME
IPv4 address.
@ SOCKS5_AT_IPV4
IPv4 address.
@ SOCKS5_AT_IPV6
IPv6 address.
static ssize_t mhd_content_cb(void *cls, uint64_t pos, char *buf, size_t max)
Callback for MHD response generation.
#define MAX_DANES
Maximum number of DANE records we support per domain name (and port and protocol).
static void kill_httpd_task(void *cls)
Task run whenever HTTP server is idle for too long.
static struct MhdHttpList * mhd_httpd_head
DLL for http/https daemons.
Socks5StatusCode
Status codes in Socks5 response.
@ SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED
@ SOCKS5_STATUS_GENERAL_FAILURE
@ SOCKS5_STATUS_COMMAND_NOT_SUPPORTED
@ SOCKS5_STATUS_REQUEST_GRANTED
static void curl_task_download(void *cls)
Task that is run when we are ready to receive more data from curl.
static struct MhdHttpList * lookup_ssl_httpd(const char *domain)
Lookup (or create) an TLS MHD instance for a particular domain.
static struct GNUNET_SCHEDULER_Task * curl_download_task
The cURL download task (curl multi API).
static size_t curl_upload_cb(void *buf, size_t size, size_t nmemb, void *cls)
cURL callback for uploaded (PUT/POST) data.
static void do_accept(void *cls)
Accept new incoming connections.
static int load_cert_from_file(gnutls_x509_crt_t crt, const char *certfile)
Load cert from file.
static void do_write(void *cls)
Write data from buffer to socks5 client, then continue with state machine.
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.
static struct Socks5Request * s5r_head
DLL of active socks requests.
static int check_ssl_certificate(struct Socks5Request *s5r)
Check that the website has presented us with a valid X.509 certificate.
#define MHD_CACHE_TIMEOUT
After how long do we clean up unused MHD TLS instances?
#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 cleanup_s5r(struct Socks5Request *s5r)
Clean up s5r handles.
static in_addr_t address
The address to bind to.
static void signal_socks_failure(struct Socks5Request *s5r, enum Socks5StatusCode sc)
Return a server response message indicating a failure to the client.
static void timeout_s5r_handshake(void *cls)
Task run when a Socks5Request somehow fails to be associated with an MHD connection (e....
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.
#define IO_BUFFERSIZE
Size of the buffer for the data upload / download.
static struct GNUNET_SCHEDULER_Task * ltask6
The listen task ID for IPv6.
static struct GNUNET_SCHEDULER_Task * ltask4
The listen task ID for IPv4.
static struct MHD_Response * curl_failure_response
Response we return on cURL failures.
static struct ProxyGNSCertificate * generate_gns_certificate(const char *name)
Generate new certificate for specific name.
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...
static char * name
Name (label) of the records to list.
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.
static char * value
Value of the record to add/remove.
static uint64_t etime
Expiration string converted to numeric value.
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition gnunet-nat.c:85
static void run_mhd_now()
Run MHD now, we have extra data ready for the callback.
static void kill_httpd()
Kill the MHD daemon.
static void schedule_httpd()
Schedule MHD.
static struct GNUNET_FS_SearchContext * sc
static void cleanup()
Cleanup task.
static struct GNUNET_VPN_RedirectionRequest * request
Opaque redirection request handle.
Definition gnunet-vpn.c:40
#define MHD_RESULT
Data type to use for functions return an "MHD result".
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.
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:235
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:687
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_DNSPARSER_TYPE_TLSA
#define GNUNET_DNSPARSER_TYPE_A
#define GNUNET_DNSPARSER_TYPE_AAAA
#define GNUNET_DNSPARSER_MAX_NAME_LENGTH
Maximum length of a name in DNS.
#define GNUNET_GETOPT_OPTION_END
Marker for the end of the list of options.
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.
void GNUNET_GNS_disconnect(struct GNUNET_GNS_Handle *handle)
Shutdown connection with the GNS service.
Definition gns_api.c:289
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 ...
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
@ GNUNET_GNS_LO_LOCAL_MASTER
For the rightmost label, only look in the cache (it is our local namestore), for the others,...
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_MIN(a, b)
@ GNUNET_SCHEDULER_PRIORITY_DEFAULT
Run with the default priority (normal P2P operations).
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
enum GNUNET_GenericReturnValue GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
void GNUNET_log_config_missing(enum GNUNET_ErrorType kind, const char *section, const char *option)
Log error message about missing configuration option.
#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...
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
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_.
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.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
struct sockaddr * GNUNET_NETWORK_get_addr(const struct GNUNET_NETWORK_Handle *desc)
Return the sockaddr for this network handle.
Definition network.c:1014
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
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition network.c:508
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition network.c:1185
socklen_t GNUNET_NETWORK_get_addrlen(const struct GNUNET_NETWORK_Handle *desc)
Return sockaddr length for this network handle.
Definition network.c:1027
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition network.c:1001
void GNUNET_NETWORK_fdset_copy_native(struct GNUNET_NETWORK_FDSet *to, const fd_set *from, int nfds)
Copy a native fd set into the GNUnet representation.
Definition network.c:1041
ssize_t GNUNET_NETWORK_socket_recv(const struct GNUNET_NETWORK_Handle *desc, void *buffer, size_t length)
Read data from a connected socket (always non-blocking).
Definition network.c:717
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition network.c:1169
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition network.c:833
ssize_t GNUNET_NETWORK_socket_send(const struct GNUNET_NETWORK_Handle *desc, const void *buffer, size_t length)
Send data (always non-blocking).
Definition network.c:738
enum GNUNET_GenericReturnValue GNUNET_NETWORK_test_pf(int pf)
Test if the given protocol family is supported by this system.
Definition network.c:79
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
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition network.c:652
int GNUNET_NETWORK_fdset_isset(const struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_NETWORK_Handle *desc)
Check whether a socket is part of the fd set.
Definition network.c:950
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
enum GNUNET_GenericReturnValue GNUNET_PROGRAM_run(const struct GNUNET_OS_ProjectData *pd, 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:407
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition scheduler.c:567
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:1511
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:1582
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:1835
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition scheduler.c:758
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:1339
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:980
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:1304
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:1277
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
#define max(x, y)
static unsigned int size
Size of the "table".
Definition peer.c:68
#define _(String)
GNU gettext support macro.
Definition platform.h:179
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition scheduler.c:431
Definition of a command line option.
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.
collection of IO descriptors
handle to a socket
Definition network.c:53
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 ...
Time for relative time used by GNUnet, in microseconds.
struct HttpResponseHeader * next
DLL.
char * type
Header type.
char * value
Header value.
A structure for all running Httpds.
struct GNUNET_SCHEDULER_Task * httpd_task
The task ID.
struct ProxyGNSCertificate * proxy_cert
Optional proxy certificate used.
char * domain
the domain name to server (only important for TLS)
struct MhdHttpList * next
DLL for httpds.
struct MHD_Daemon * daemon
The daemon handle.
int is_ssl
is this an ssl daemon?
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.
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.
A structure for socks requests.
int suspended
Did we suspend MHD processing?
struct GNUNET_SCHEDULER_Task * rtask
Client socket read task.
CURL * curl
Handle to cURL.
size_t io_len
Number of bytes already in the IO buffer.
struct MHD_Response * response
MHD response object for this request.
struct Socks5Request * next
DLL.
enum SocksPhase state
The socks state.
struct HttpResponseHeader * header_head
Headers from response.
int is_tls
This is (probably) a TLS connection.
struct HttpResponseHeader * header_tail
Headers from response.
char * domain
the domain name to server (only important for TLS)
char * url
The URL to fetch.
size_t rbuf_len
Number of bytes already in read buffer.
int is_gns
Was the hostname resolved via GNS?
uint16_t port
Desired destination port.
int ssl_checked
X.509 Certificate status.
struct GNUNET_GNS_LookupWithTldRequest * gns_lookup
Handle to GNS lookup, during SOCKS5_RESOLVING phase.
int dane_data_len[32+1]
Number of bytes in dane_data.
struct GNUNET_SCHEDULER_Task * timeout_task
Timeout task.
struct MHD_Connection * con
MHD connection for this request.
char rbuf[(256+32)]
Read buffer.
char wbuf[(256+32)]
Write buffer.
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.
int curl_paused
Did we pause CURL processing?
struct sockaddr_storage destination_address
Once known, what's the target address for the connection?
struct curl_slist * headers
HTTP request headers for the curl request.
struct MhdHttpList * hd
MHD HTTP instance handling this request, NULL for none.
char * dane_data[32+1]
Payload of the DANE records encountered.
char io_buf[CURL_MAX_WRITE_SIZE]
Buffer we use for moving data between MHD and curl (in both directions).
unsigned int response_code
HTTP response code to give to MHD for the response.
struct GNUNET_SCHEDULER_Task * wtask
Client socket write task.
size_t wbuf_len
Number of bytes already in write buffer.
struct GNUNET_NETWORK_Handle * sock
The client socket.
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.
Server response to client requests in Socks5 protocol.

◆ HTTP_HANDSHAKE_TIMEOUT

#define HTTP_HANDSHAKE_TIMEOUT
Value:
#define GNUNET_TIME_UNIT_SECONDS
One second.

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

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

◆ LOG_CURL_EASY

#define LOG_CURL_EASY (   level,
  fun,
  rc 
)
Value:
GNUNET_log (level, \
_ ("%s failed at %s:%d: `%s'\n"), \
fun, \
__FILE__, \
__LINE__, \
curl_easy_strerror (rc))

Log curl error.

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

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

114 :%d: `%s'\n"), \
115 fun, \
116 __FILE__, \
117 __LINE__, \
118 curl_easy_strerror (rc))

◆ SOCKS_VERSION_5

#define SOCKS_VERSION_5   0x05

Which SOCKS version do we speak?

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

◆ SOCKS_AUTH_NONE

#define SOCKS_AUTH_NONE   0

Flag to set for 'no authentication'.

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

Enumeration Type Documentation

◆ Socks5Commands

Commands in Socks5.

Enumerator
SOCKS5_CMD_TCP_STREAM 

Establish TCP/IP stream.

SOCKS5_CMD_TCP_PORT 

Establish TCP port binding.

SOCKS5_CMD_UDP_PORT 

Establish UDP port binding.

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

138{
143
148
153};
@ SOCKS5_CMD_UDP_PORT
Establish UDP port binding.
@ SOCKS5_CMD_TCP_PORT
Establish TCP port binding.

◆ Socks5AddressType

Address types in Socks5.

Enumerator
SOCKS5_AT_IPV4 

IPv4 address.

SOCKS5_AT_DOMAINNAME 

IPv4 address.

SOCKS5_AT_IPV6 

IPv6 address.

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

160{
164 SOCKS5_AT_IPV4 = 1,
165
170
175};

◆ Socks5StatusCode

Status codes in Socks5 response.

Enumerator
SOCKS5_STATUS_REQUEST_GRANTED 
SOCKS5_STATUS_GENERAL_FAILURE 
SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE 
SOCKS5_STATUS_NETWORK_UNREACHABLE 
SOCKS5_STATUS_HOST_UNREACHABLE 
SOCKS5_STATUS_CONNECTION_REFUSED_BY_HOST 
SOCKS5_STATUS_TTL_EXPIRED 
SOCKS5_STATUS_COMMAND_NOT_SUPPORTED 
SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED 

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

◆ SocksPhase

enum SocksPhase

The socks phases.

Enumerator
SOCKS5_INIT 

We're waiting to get the client hello.

SOCKS5_REQUEST 

We're waiting to get the initial request.

SOCKS5_RESOLVING 

We are currently resolving the destination.

SOCKS5_DATA_TRANSFER 

We're in transfer mode.

SOCKS5_WRITE_THEN_CLEANUP 

Finish writing the write buffer, then clean up.

SOCKS5_SOCKET_WITH_MHD 

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

SOCKS5_SOCKET_UPLOAD_STARTED 

We've started receiving upload data from MHD.

SOCKS5_SOCKET_UPLOAD_DONE 

We've finished receiving upload data from MHD.

SOCKS5_SOCKET_DOWNLOAD_STARTED 

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

SOCKS5_SOCKET_DOWNLOAD_DONE 

We've finished receiving download data from cURL.

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

Function Documentation

◆ run_mhd_now()

static void run_mhd_now ( struct MhdHttpList hd)
static

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

Parameters
hdthe daemon to run now.

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

2585{
2586 if (NULL != hd->httpd_task)
2589 hd);
2590}

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

Here is the call graph for this function:

◆ cleanup_s5r()

static void cleanup_s5r ( struct Socks5Request s5r)
static

Clean up s5r handles.

Parameters
s5rthe handle to destroy

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

773{
775 "Cleaning up socks request\n");
776 if (NULL != s5r->curl)
777 {
779 "Cleaning up cURL handle\n");
780 curl_multi_remove_handle (curl_multi,
781 s5r->curl);
782 curl_easy_cleanup (s5r->curl);
783 s5r->curl = NULL;
784 }
785 if (s5r->suspended)
786 {
787 s5r->suspended = GNUNET_NO;
788 MHD_resume_connection (s5r->con);
789 }
790 curl_slist_free_all (s5r->headers);
791 if (NULL != s5r->hosts)
792 {
793 curl_slist_free_all (s5r->hosts);
794 }
795 if ((NULL != s5r->response) &&
797 {
798 MHD_destroy_response (s5r->response);
799 s5r->response = NULL;
800 }
801 if (NULL != s5r->rtask)
802 {
804 s5r->rtask = NULL;
805 }
806 if (NULL != s5r->timeout_task)
807 {
809 s5r->timeout_task = NULL;
810 }
811 if (NULL != s5r->wtask)
812 {
814 s5r->wtask = NULL;
815 }
816 if (NULL != s5r->gns_lookup)
817 {
819 s5r->gns_lookup = NULL;
820 }
821 if (NULL != s5r->sock)
822 {
823 if (SOCKS5_SOCKET_WITH_MHD <= s5r->state)
825 else
827 s5r->sock = NULL;
828 }
830 s5r_tail,
831 s5r);
832 GNUNET_free (s5r->domain);
833 GNUNET_free (s5r->leho);
834 GNUNET_free (s5r->url);
835 for (unsigned int i = 0; i < s5r->num_danes; i++)
836 GNUNET_free (s5r->dane_data[i]);
837 GNUNET_free (s5r);
838}
static int state
The current state of the parser.
void * GNUNET_GNS_lookup_with_tld_cancel(struct GNUNET_GNS_LookupWithTldRequest *ltr)
Cancel pending lookup request.
void GNUNET_NETWORK_socket_free_memory_only_(struct GNUNET_NETWORK_Handle *desc)
Only free memory of a socket, keep the file descriptor untouched.
Definition network.c:566

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

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

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

◆ curl_download_prepare()

static void curl_download_prepare ( void  )
static

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

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

1570{
1571 CURLMcode mret;
1572 fd_set rs;
1573 fd_set ws;
1574 fd_set es;
1575 int max;
1576 struct GNUNET_NETWORK_FDSet *grs;
1577 struct GNUNET_NETWORK_FDSet *gws;
1578 long to;
1579 struct GNUNET_TIME_Relative rtime;
1580
1582 "Scheduling CURL interaction\n");
1583 if (NULL != curl_download_task)
1584 {
1586 curl_download_task = NULL;
1587 }
1588 max = -1;
1589 FD_ZERO (&rs);
1590 FD_ZERO (&ws);
1591 FD_ZERO (&es);
1592 if (CURLM_OK != (mret = curl_multi_fdset (curl_multi,
1593 &rs,
1594 &ws,
1595 &es,
1596 &max)))
1597 {
1599 "%s failed at %s:%d: `%s'\n",
1600 "curl_multi_fdset", __FILE__, __LINE__,
1601 curl_multi_strerror (mret));
1602 return;
1603 }
1604 to = -1;
1605 GNUNET_break (CURLM_OK ==
1606 curl_multi_timeout (curl_multi,
1607 &to));
1608 if (-1 == to)
1610 else
1612 to);
1613 if (-1 != max)
1614 {
1618 &rs,
1619 max + 1);
1621 &ws,
1622 max + 1);
1625 rtime,
1626 grs,
1627 gws,
1629 curl_multi);
1632 }
1633 else
1634 {
1637 curl_multi);
1638 }
1639}

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

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

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

◆ mhd_content_cb()

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

Callback for MHD response generation.

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

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

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

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

References Socks5Request::con, Socks5Request::curl, curl_download_prepare(), Socks5Request::curl_paused, Socks5Request::domain, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_MIN, GNUNET_NO, GNUNET_YES, Socks5Request::io_buf, Socks5Request::io_len, max, SOCKS5_SOCKET_DOWNLOAD_DONE, SOCKS5_SOCKET_UPLOAD_DONE, SOCKS5_SOCKET_UPLOAD_STARTED, Socks5Request::state, Socks5Request::suspended, and Socks5Request::url.

Referenced by create_mhd_response_from_s5r().

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

◆ check_ssl_certificate()

static int check_ssl_certificate ( struct Socks5Request s5r)
static

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

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

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

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

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

References _, Socks5Request::curl, Socks5Request::dane_data, Socks5Request::dane_data_len, Socks5Request::domain, GNUNET_break, GNUNET_DNSPARSER_MAX_NAME_LENGTH, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_NO, GNUNET_OK, GNUNET_SYSERR, GNUNET_YES, Socks5Request::leho, name, Socks5Request::num_danes, size, Socks5Request::ssl_checked, and verify.

Referenced by curl_check_hdr().

Here is the caller graph for this function:

◆ curl_check_hdr()

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

We're getting an HTTP response header from cURL.

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

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

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

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

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

Referenced by create_response().

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

◆ create_mhd_response_from_s5r()

static int create_mhd_response_from_s5r ( struct Socks5Request s5r)
static

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

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

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

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

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(), Socks5Request::response, Socks5Request::response_code, Socks5Request::suspended, and Socks5Request::url.

Referenced by curl_download_cb(), and curl_task_download().

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

◆ curl_download_cb()

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

Handle response payload data from cURL.

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

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

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

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

References Socks5Request::con, create_mhd_response_from_s5r(), ctx, Socks5Request::curl_paused, Socks5Request::domain, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_NO, GNUNET_OK, GNUNET_YES, Socks5Request::hd, Socks5Request::io_buf, Socks5Request::io_len, Socks5Request::response, run_mhd_now(), size, SOCKS5_SOCKET_DOWNLOAD_STARTED, SOCKS5_SOCKET_UPLOAD_DONE, SOCKS5_SOCKET_UPLOAD_STARTED, Socks5Request::state, Socks5Request::suspended, and Socks5Request::url.

Referenced by create_response().

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

◆ curl_upload_cb()

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

cURL callback for uploaded (PUT/POST) data.

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

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

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

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

References Socks5Request::curl, Socks5Request::curl_paused, Socks5Request::domain, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_MIN, GNUNET_NO, GNUNET_YES, Socks5Request::hd, Socks5Request::io_buf, Socks5Request::io_len, run_mhd_now(), size, SOCKS5_SOCKET_DOWNLOAD_STARTED, SOCKS5_SOCKET_UPLOAD_DONE, SOCKS5_SOCKET_UPLOAD_STARTED, Socks5Request::state, and Socks5Request::url.

Referenced by create_response().

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

◆ curl_task_download()

static void curl_task_download ( void *  cls)
static

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

Parameters
clsclosure
clsclosure, NULL

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

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

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

Referenced by curl_download_prepare().

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

◆ con_val_iter()

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

Read HTTP request header field from the request.

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

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

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

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

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

Referenced by create_response().

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

◆ create_response()

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

Main MHD callback for handling requests.

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

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

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

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

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

Referenced by lookup_ssl_httpd(), and run().

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

◆ mhd_completed_cb()

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

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

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

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

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

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

Referenced by lookup_ssl_httpd(), and run().

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

◆ mhd_connection_cb()

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

Function called when MHD connection is opened or closed.

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

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

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

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

Referenced by lookup_ssl_httpd(), and run().

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

◆ mhd_log_callback()

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

Function called when MHD first processes an incoming connection.

Gives us the respective URI information.

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

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

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

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

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

Referenced by lookup_ssl_httpd(), and run().

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

◆ kill_httpd()

static void kill_httpd ( struct MhdHttpList hd)
static

Kill the given MHD daemon.

Parameters
hddaemon to stop

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

2445{
2448 hd);
2449 GNUNET_free (hd->domain);
2450 MHD_stop_daemon (hd->daemon);
2451 if (NULL != hd->httpd_task)
2452 {
2454 hd->httpd_task = NULL;
2455 }
2456 GNUNET_free (hd->proxy_cert);
2457 if (hd == httpd)
2458 httpd = NULL;
2459 GNUNET_free (hd);
2460}

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.

Here is the call graph for this function:

◆ kill_httpd_task()

static void kill_httpd_task ( void *  cls)
static

Task run whenever HTTP server is idle for too long.

Kill it.

Parameters
clsthe struct MhdHttpList *

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

2470{
2471 struct MhdHttpList *hd = cls;
2472
2473 hd->httpd_task = NULL;
2474 kill_httpd (hd);
2475}

References MhdHttpList::httpd_task, and kill_httpd().

Referenced by schedule_httpd().

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

◆ do_httpd()

static void do_httpd ( void *  cls)
static

Task run whenever HTTP server operations are pending.

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

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

2569{
2570 struct MhdHttpList *hd = cls;
2571
2572 hd->httpd_task = NULL;
2573 MHD_run (hd->daemon);
2574 schedule_httpd (hd);
2575}

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

Referenced by run_mhd_now(), and schedule_httpd().

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

◆ schedule_httpd()

static void schedule_httpd ( struct MhdHttpList hd)
static

Schedule MHD.

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

Parameters
hdthe daemon to schedule

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

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

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.

Here is the call graph for this function:

◆ load_file()

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

Read file in filename.

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

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

2603{
2604 void *buffer;
2605 uint64_t fsize;
2606
2607 if (GNUNET_OK !=
2609 &fsize,
2610 GNUNET_YES,
2611 GNUNET_YES))
2612 return NULL;
2613 if (fsize > MAX_PEM_SIZE)
2614 return NULL;
2615 *size = (unsigned int) fsize;
2616 buffer = GNUNET_malloc (*size);
2617 if (fsize !=
2619 buffer,
2620 (size_t) fsize))
2621 {
2622 GNUNET_free (buffer);
2623 return NULL;
2624 }
2625 return buffer;
2626}

References filename, GNUNET_DISK_file_size(), GNUNET_DISK_fn_read(), GNUNET_free, GNUNET_malloc, GNUNET_OK, GNUNET_YES, MAX_PEM_SIZE, and size.

Referenced by load_cert_from_file(), and load_key_from_file().

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

◆ load_key_from_file()

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

Load PEM key from file.

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

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

2639{
2640 gnutls_datum_t key_data;
2641 int ret;
2642
2643 key_data.data = load_file (keyfile,
2644 &key_data.size);
2645 if (NULL == key_data.data)
2646 return GNUNET_SYSERR;
2647 ret = gnutls_x509_privkey_import (key, &key_data,
2648 GNUTLS_X509_FMT_PEM);
2649 if (GNUTLS_E_SUCCESS != ret)
2650 {
2652 _ ("Unable to import private key from file `%s'\n"),
2653 keyfile);
2654 }
2655 GNUNET_free (key_data.data);
2656 return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2657}

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

Referenced by run().

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

◆ load_cert_from_file()

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

Load cert from file.

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

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

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

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

Referenced by run().

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

◆ generate_gns_certificate()

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

Generate new certificate for specific name.

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

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

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

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

Referenced by lookup_ssl_httpd().

Here is the caller graph for this function:

◆ mhd_error_log_callback()

static void mhd_error_log_callback ( void *  cls,
const char *  fm,
va_list  ap 
)
static

Function called by MHD with errors, suppresses them all.

Parameters
clsclosure
fmformat string (printf()-style)
aparguments to fm

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

2784{
2785 /* do nothing */
2786}

Referenced by lookup_ssl_httpd().

Here is the caller graph for this function:

◆ lookup_ssl_httpd()

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

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

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

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

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

References ProxyGNSCertificate::cert, create_response(), MhdHttpList::daemon, MhdHttpList::domain, generate_gns_certificate(), GNUNET_break, GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_new, GNUNET_strdup, GNUNET_YES, MhdHttpList::is_ssl, ProxyGNSCertificate::key, mhd_completed_cb(), mhd_connection_cb(), mhd_error_log_callback(), mhd_httpd_head, mhd_httpd_tail, mhd_log_callback(), MhdHttpList::next, and MhdHttpList::proxy_cert.

Referenced by setup_data_transfer().

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

◆ timeout_s5r_handshake()

static void timeout_s5r_handshake ( void *  cls)
static

Task run when a Socks5Request somehow fails to be associated with an MHD connection (e.g.

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

Parameters
clsthe struct Socks5Request *

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

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

References cleanup_s5r(), and Socks5Request::timeout_task.

Referenced by setup_data_transfer().

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

◆ setup_data_transfer()

static void setup_data_transfer ( struct Socks5Request s5r)
static

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

Parameters
s5rsocks request that has reached the final stage

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

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

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

Referenced by do_write().

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

◆ do_write()

static void do_write ( void *  cls)
static

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

Parameters
clsthe closure with the struct Socks5Request

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

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

References cleanup_s5r(), do_write(), GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_NETWORK_socket_send(), GNUNET_SCHEDULER_add_write_net(), GNUNET_TIME_UNIT_FOREVER_REL, Socks5Request::rtask, setup_data_transfer(), Socks5Request::sock, SOCKS5_DATA_TRANSFER, SOCKS5_INIT, SOCKS5_REQUEST, SOCKS5_WRITE_THEN_CLEANUP, Socks5Request::state, Socks5Request::wbuf, Socks5Request::wbuf_len, and Socks5Request::wtask.

Referenced by do_s5r_read(), do_write(), signal_socks_failure(), and signal_socks_success().

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

◆ signal_socks_failure()

static void signal_socks_failure ( struct Socks5Request s5r,
enum Socks5StatusCode  sc 
)
static

Return a server response message indicating a failure to the client.

Parameters
s5rrequest to return failure code for
scstatus code to return

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

3007{
3008 struct Socks5ServerResponseMessage *s_resp;
3009
3010 GNUNET_break (0 == s5r->wbuf_len); /* Should happen first in any transmission, right? */
3012 sizeof(struct Socks5ServerResponseMessage));
3013 s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3014 memset (s_resp, 0, sizeof(struct Socks5ServerResponseMessage));
3015 s_resp->version = SOCKS_VERSION_5;
3016 s_resp->reply = sc;
3018 if (NULL != s5r->wtask)
3019 s5r->wtask =
3021 s5r->sock,
3022 &do_write, s5r);
3023}

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

Referenced by do_s5r_read(), and handle_gns_result().

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

◆ signal_socks_success()

static void signal_socks_success ( struct Socks5Request s5r)
static

Return a server response message indicating success.

Parameters
s5rrequest to return success status message for

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

3033{
3034 struct Socks5ServerResponseMessage *s_resp;
3035
3036 s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3037 s_resp->version = SOCKS_VERSION_5;
3038 s_resp->reply = SOCKS5_STATUS_REQUEST_GRANTED;
3039 s_resp->reserved = 0;
3040 s_resp->addr_type = SOCKS5_AT_IPV4;
3041 /* zero out IPv4 address and port */
3042 memset (&s_resp[1],
3043 0,
3044 sizeof(struct in_addr) + sizeof(uint16_t));
3045 s5r->wbuf_len += sizeof(struct Socks5ServerResponseMessage)
3046 + sizeof(struct in_addr) + sizeof(uint16_t);
3047 if (NULL == s5r->wtask)
3048 s5r->wtask =
3050 s5r->sock,
3051 &do_write, s5r);
3052}

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

Referenced by do_s5r_read(), and handle_gns_result().

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

◆ handle_gns_result()

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

Process GNS results for target domain.

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

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

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

References Socks5Request::dane_data, Socks5Request::dane_data_len, GNUNET_GNSRECORD_Data::data, GNUNET_GNSRECORD_Data::data_size, Socks5Request::destination_address, disable_v6, Socks5Request::gns_lookup, GNUNET_break, GNUNET_break_op, GNUNET_DNSPARSER_TYPE_A, GNUNET_DNSPARSER_TYPE_AAAA, GNUNET_DNSPARSER_TYPE_TLSA, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_GNSRECORD_TYPE_BOX, GNUNET_GNSRECORD_TYPE_LEHO, GNUNET_GNSRECORD_TYPE_VPN, GNUNET_log, GNUNET_memcpy, GNUNET_memdup, GNUNET_NETWORK_test_pf(), GNUNET_NO, GNUNET_OK, GNUNET_strndup, GNUNET_YES, Socks5Request::is_gns, Socks5Request::is_tls, Socks5Request::leho, MAX_DANES, Socks5Request::num_danes, Socks5Request::port, GNUNET_GNSRECORD_BoxRecord::protocol, rd, rd_count, GNUNET_GNSRECORD_Data::record_type, GNUNET_GNSRECORD_BoxRecord::record_type, GNUNET_GNSRECORD_BoxRecord::service, signal_socks_failure(), signal_socks_success(), SOCKS5_DATA_TRANSFER, SOCKS5_STATUS_GENERAL_FAILURE, and Socks5Request::state.

Referenced by do_s5r_read().

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

◆ clear_from_s5r_rbuf()

static void clear_from_s5r_rbuf ( struct Socks5Request s5r,
size_t  len 
)
static

Remove the first len bytes from the beginning of the read buffer.

Parameters
s5rthe handle clear the read buffer for
lennumber of bytes in read buffer to advance

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

3205{
3206 GNUNET_assert (len <= s5r->rbuf_len);
3207 memmove (s5r->rbuf,
3208 &s5r->rbuf[len],
3209 s5r->rbuf_len - len);
3210 s5r->rbuf_len -= len;
3211}

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

Referenced by do_s5r_read().

Here is the caller graph for this function:

◆ do_s5r_read()

static void do_s5r_read ( void *  cls)
static

Read data from incoming Socks5 connection.

Parameters
clsthe closure with the struct Socks5Request

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

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

References _, Socks5ClientRequestMessage::addr_type, Socks5ServerHelloMessage::auth_method, cleanup_s5r(), clear_from_s5r_rbuf(), Socks5ClientRequestMessage::command, Socks5Request::destination_address, do_s5r_read(), do_write(), Socks5Request::domain, gns_handle, Socks5Request::gns_lookup, GNUNET_assert, GNUNET_break_op, GNUNET_DNSPARSER_TYPE_A, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_GNS_LO_LOCAL_MASTER, GNUNET_GNS_lookup_with_tld(), GNUNET_log, GNUNET_NETWORK_fdset_isset(), GNUNET_NETWORK_socket_recv(), GNUNET_NO, GNUNET_SCHEDULER_add_read_net(), GNUNET_SCHEDULER_add_write_net(), GNUNET_SCHEDULER_cancel(), GNUNET_SCHEDULER_get_task_context(), GNUNET_strndup, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, handle_gns_result(), HTTPS_PORT, Socks5Request::is_tls, Socks5ClientHelloMessage::num_auth_methods, Socks5Request::port, Socks5Request::rbuf, Socks5Request::rbuf_len, GNUNET_SCHEDULER_TaskContext::read_ready, Socks5Request::rtask, signal_socks_failure(), signal_socks_success(), Socks5Request::sock, SOCKS5_AT_DOMAINNAME, SOCKS5_AT_IPV4, SOCKS5_AT_IPV6, SOCKS5_CMD_TCP_STREAM, SOCKS5_DATA_TRANSFER, SOCKS5_INIT, SOCKS5_REQUEST, SOCKS5_RESOLVING, SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED, SOCKS5_STATUS_COMMAND_NOT_SUPPORTED, SOCKS5_STATUS_GENERAL_FAILURE, SOCKS_AUTH_NONE, SOCKS_VERSION_5, Socks5Request::state, tc, Socks5ClientHelloMessage::version, Socks5ServerHelloMessage::version, Socks5Request::wbuf, Socks5Request::wbuf_len, and Socks5Request::wtask.

Referenced by do_accept(), and do_s5r_read().

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

◆ do_accept()

static void do_accept ( void *  cls)
static

Accept new incoming connections.

Parameters
clsthe closure with the lsock4 or lsock6

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

3434{
3435 struct GNUNET_NETWORK_Handle *lsock = cls;
3436 struct GNUNET_NETWORK_Handle *s;
3437 struct Socks5Request *s5r;
3438
3439 GNUNET_assert (NULL != lsock);
3440 if (lsock == lsock4)
3442 lsock,
3443 &do_accept,
3444 lsock);
3445 else if (lsock == lsock6)
3447 lsock,
3448 &do_accept,
3449 lsock);
3450 else
3451 GNUNET_assert (0);
3453 NULL,
3454 NULL);
3455 if (NULL == s)
3456 {
3458 "accept");
3459 return;
3460 }
3462 "Got an inbound connection, waiting for data\n");
3463 s5r = GNUNET_new (struct Socks5Request);
3465 s5r_tail,
3466 s5r);
3467 s5r->sock = s;
3468 s5r->state = SOCKS5_INIT;
3470 s5r->sock,
3471 &do_s5r_read,
3472 s5r);
3473}

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

3486{
3488 "Shutting down...\n");
3489 /* MHD requires resuming before destroying the daemons */
3490 for (struct Socks5Request *s5r = s5r_head;
3491 NULL != s5r;
3492 s5r = s5r->next)
3493 {
3494 if (s5r->suspended)
3495 {
3496 s5r->suspended = GNUNET_NO;
3497 MHD_resume_connection (s5r->con);
3498 }
3499 }
3500 while (NULL != mhd_httpd_head)
3502 while (NULL != s5r_head)
3504 if (NULL != lsock4)
3505 {
3507 lsock4 = NULL;
3508 }
3509 if (NULL != lsock6)
3510 {
3512 lsock6 = NULL;
3513 }
3514 if (NULL != curl_multi)
3515 {
3516 curl_multi_cleanup (curl_multi);
3517 curl_multi = NULL;
3518 }
3519 if (NULL != gns_handle)
3520 {
3522 gns_handle = NULL;
3523 }
3524 if (NULL != curl_download_task)
3525 {
3527 curl_download_task = NULL;
3528 }
3529 if (NULL != ltask4)
3530 {
3532 ltask4 = NULL;
3533 }
3534 if (NULL != ltask6)
3535 {
3537 ltask6 = NULL;
3538 }
3539 gnutls_x509_crt_deinit (proxy_ca.cert);
3540 gnutls_x509_privkey_deinit (proxy_ca.key);
3541 gnutls_global_deinit ();
3542}

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.

Here is the call 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 3551 of file gnunet-gns-proxy.c.

3552{
3553 struct GNUNET_NETWORK_Handle *ls;
3554 struct sockaddr_in sa4;
3555 int eno;
3556
3557 memset (&sa4, 0, sizeof(sa4));
3558 sa4.sin_family = AF_INET;
3559 sa4.sin_port = htons (port);
3560 sa4.sin_addr.s_addr = address;
3561#if HAVE_SOCKADDR_IN_SIN_LEN
3562 sa4.sin_len = sizeof(sa4);
3563#endif
3565 SOCK_STREAM,
3566 0);
3567 if (NULL == ls)
3568 return NULL;
3569 if (GNUNET_OK !=
3571 (const struct sockaddr *) &sa4,
3572 sizeof(sa4)))
3573 {
3574 eno = errno;
3576 errno = eno;
3577 return NULL;
3578 }
3579 return ls;
3580}

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

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

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

3634{
3635 char*cafile_cfg = NULL;
3636 char*cafile;
3637 char*addr_str;
3638 struct MhdHttpList *hd;
3639
3640 cfg = c;
3641
3642 /* Get address to bind to */
3644 "BIND_TO",
3645 &addr_str))
3646 {
3647 // No address specified
3649 "Don't know what to bind to...\n");
3650 GNUNET_free (addr_str);
3652 return;
3653 }
3654 if (1 != inet_pton (AF_INET, addr_str, &address))
3655 {
3657 "Unable to parse address %s\n",
3658 addr_str);
3659 GNUNET_free (addr_str);
3661 return;
3662 }
3663 GNUNET_free (addr_str);
3664 /* Get address to bind to */
3666 "BIND_TO6",
3667 &addr_str))
3668 {
3669 // No address specified
3671 "Don't know what to bind6 to...\n");
3672 GNUNET_free (addr_str);
3674 return;
3675 }
3676 if (1 != inet_pton (AF_INET6, addr_str, &address6))
3677 {
3679 "Unable to parse IPv6 address %s\n",
3680 addr_str);
3681 GNUNET_free (addr_str);
3683 return;
3684 }
3685 GNUNET_free (addr_str);
3686
3687 if (NULL == (curl_multi = curl_multi_init ()))
3688 {
3690 "Failed to create cURL multi handle!\n");
3691 return;
3692 }
3693 cafile = cafile_opt;
3694 if (NULL == cafile)
3695 {
3696 if (GNUNET_OK !=
3698 "gns-proxy",
3699 "PROXY_CACERT",
3700 &cafile_cfg))
3701 {
3703 "gns-proxy",
3704 "PROXY_CACERT");
3705 return;
3706 }
3707 cafile = cafile_cfg;
3708 }
3710 "Using `%s' as CA\n",
3711 cafile);
3712
3713 gnutls_global_init ();
3714 gnutls_x509_crt_init (&proxy_ca.cert);
3715 gnutls_x509_privkey_init (&proxy_ca.key);
3716
3717 if ((GNUNET_OK !=
3719 cafile)) ||
3720 (GNUNET_OK !=
3722 cafile)))
3723 {
3725 _ ("Failed to load X.509 key and certificate from `%s'\n"),
3726 cafile);
3727 gnutls_x509_crt_deinit (proxy_ca.cert);
3728 gnutls_x509_privkey_deinit (proxy_ca.key);
3729 gnutls_global_deinit ();
3730 GNUNET_free (cafile_cfg);
3731 return;
3732 }
3733 GNUNET_free (cafile_cfg);
3734 if (NULL == (gns_handle = GNUNET_GNS_connect (cfg)))
3735 {
3737 "Unable to connect to GNS!\n");
3738 gnutls_x509_crt_deinit (proxy_ca.cert);
3739 gnutls_x509_privkey_deinit (proxy_ca.key);
3740 gnutls_global_deinit ();
3741 return;
3742 }
3744 NULL);
3745
3746 /* Open listen socket for socks proxy */
3747 lsock6 = bind_v6 ();
3748 if (NULL == lsock6)
3749 {
3751 "bind");
3752 }
3753 else
3754 {
3755 if (GNUNET_OK !=
3757 5))
3758 {
3760 "listen");
3762 lsock6 = NULL;
3763 }
3764 else
3765 {
3767 lsock6,
3768 &do_accept,
3769 lsock6);
3770 }
3771 }
3772 lsock4 = bind_v4 ();
3773 if (NULL == lsock4)
3774 {
3776 "bind");
3777 }
3778 else
3779 {
3780 if (GNUNET_OK !=
3782 5))
3783 {
3785 "listen");
3787 lsock4 = NULL;
3788 }
3789 else
3790 {
3792 lsock4,
3793 &do_accept,
3794 lsock4);
3795 }
3796 }
3797 if ((NULL == lsock4) &&
3798 (NULL == lsock6))
3799 {
3801 return;
3802 }
3803 if (CURLSSLSET_OK != curl_global_sslset (CURLSSLBACKEND_GNUTLS,
3804 NULL,
3805 NULL))
3806 {
3808 "cURL does not support the GnuTLS backend\n");
3809
3810 }
3811 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
3812 {
3814 "cURL global init failed!\n");
3816 return;
3817 }
3819 "Proxy listens on port %u\n",
3820 (unsigned int) port);
3821
3822 /* start MHD daemon for HTTP */
3823 hd = GNUNET_new (struct MhdHttpList);
3824 hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
3825 | MHD_ALLOW_SUSPEND_RESUME,
3826 0,
3827 NULL, NULL,
3828 &create_response, hd,
3829 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
3830 int) 16,
3831 MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
3832 NULL,
3833 MHD_OPTION_NOTIFY_CONNECTION,
3834 &mhd_connection_cb, NULL,
3835 MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
3836 NULL,
3837 MHD_OPTION_END);
3838 if (NULL == hd->daemon)
3839 {
3840 GNUNET_free (hd);
3842 return;
3843 }
3844 httpd = hd;
3847 hd);
3848}

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

3861{
3864 "port",
3865 NULL,
3866 gettext_noop (
3867 "listen on specified port (default: 7777)"),
3868 &port),
3870 "authority",
3871 NULL,
3872 gettext_noop ("pem file to use as CA"),
3873 &cafile_opt),
3875 "disable-ivp6",
3876 gettext_noop ("disable use of IPv6"),
3877 &disable_v6),
3878
3880 };
3881 static const char*page =
3882 "<html><head><title>gnunet-gns-proxy</title>"
3883 "</head><body>cURL fail</body></html>";
3884 int ret;
3885
3886 GNUNET_log_setup ("gnunet-gns-proxy",
3887 "WARNING",
3888 NULL);
3890 = MHD_create_response_from_buffer (strlen (page),
3891 (void *) page,
3892 MHD_RESPMEM_PERSISTENT);
3893
3894 ret =
3895 (GNUNET_OK ==
3897 argc, argv,
3898 "gnunet-gns-proxy",
3899 _ ("GNUnet GNS proxy"),
3900 options,
3901 &run, NULL)) ? 0 : 1;
3902 MHD_destroy_response (curl_failure_response);
3903 return ret;
3904}

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

Here is the call graph for this function:

Variable Documentation

◆ address

in_addr_t address
static

The address to bind to.

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

Referenced by bind_v4(), and run().

◆ address6

struct in6_addr address6
static

The IPv6 address to bind to.

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

Referenced by bind_v6(), and run().

◆ port

uint16_t port = 7777
static

The port the proxy is running on (default 7777)

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

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

◆ cafile_opt

char* cafile_opt
static

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

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

Referenced by main(), and run().

◆ lsock4

struct GNUNET_NETWORK_Handle* lsock4
static

The listen socket of the proxy for IPv4.

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

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

◆ lsock6

struct GNUNET_NETWORK_Handle* lsock6
static

The listen socket of the proxy for IPv6.

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

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

◆ ltask4

struct GNUNET_SCHEDULER_Task* ltask4
static

The listen task ID for IPv4.

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

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

◆ ltask6

struct GNUNET_SCHEDULER_Task* ltask6
static

The listen task ID for IPv6.

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

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

◆ curl_download_task

struct GNUNET_SCHEDULER_Task* curl_download_task
static

The cURL download task (curl multi API).

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

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

◆ curl_multi

CURLM* curl_multi
static

◆ gns_handle

struct GNUNET_GNS_Handle* gns_handle
static

Handle to the GNS service.

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

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

◆ disable_v6

int disable_v6
static

Disable IPv6.

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

Referenced by handle_gns_result(), main(), mq_init(), and tcp_address_to_sockaddr_port_only().

◆ mhd_httpd_head

struct MhdHttpList* mhd_httpd_head
static

DLL for http/https daemons.

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

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

◆ mhd_httpd_tail

struct MhdHttpList* mhd_httpd_tail
static

DLL for http/https daemons.

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

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

◆ httpd

struct MhdHttpList* httpd
static

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

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

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

◆ s5r_head

struct Socks5Request* s5r_head
static

DLL of active socks requests.

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

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

◆ s5r_tail

struct Socks5Request* s5r_tail
static

DLL of active socks requests.

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

Referenced by cleanup_s5r(), and do_accept().

◆ proxy_ca

struct ProxyCA proxy_ca
static

The CA for X.509 certificate generation.

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

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

◆ curl_failure_response

struct MHD_Response* curl_failure_response
static

Response we return on cURL failures.

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

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

◆ cfg

const struct GNUNET_CONFIGURATION_Handle* cfg
static

Our configuration.

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

Referenced by run().