GNUnet  0.10.x
gnunet-gns-proxy.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2012-2018 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
30 #include "platform.h"
31 #include <microhttpd.h>
32 /* Just included for the right curl.h */
33 #include "gnunet_curl_lib.h"
34 #include <gnutls/gnutls.h>
35 #include <gnutls/x509.h>
36 #include <gnutls/abstract.h>
37 #include <gnutls/crypto.h>
38 #if HAVE_GNUTLS_DANE
39 #include <gnutls/dane.h>
40 #endif
41 #include <regex.h>
42 #include "gnunet_util_lib.h"
43 #include "gnunet_gns_service.h"
45 #include "gns.h"
46 
47 
48 
52 #define GNUNET_GNS_PROXY_PORT 7777
53 
58 #define MAX_HTTP_URI_LENGTH 2048
59 
64 #define MAX_DANES 32
65 
70 #define IO_BUFFERSIZE CURL_MAX_WRITE_SIZE
71 
77 #define SOCKS_BUFFERSIZE (256 + 32)
78 
82 #define HTTP_PORT 80
83 
87 #define HTTPS_PORT 443
88 
92 #define MAX_PEM_SIZE (10 * 1024)
93 
97 #define MHD_CACHE_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
98 
103 #define HTTP_HANDSHAKE_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 15)
104 
105 
113 #define LOG_CURL_EASY(level, fun, rc) \
114  GNUNET_log(level, \
115  _("%s failed at %s:%d: `%s'\n"), \
116  fun, \
117  __FILE__, \
118  __LINE__, \
119  curl_easy_strerror(rc))
120 
121 
122 /* *************** Socks protocol definitions (move to TUN?) ****************** */
123 
127 #define SOCKS_VERSION_5 0x05
128 
132 #define SOCKS_AUTH_NONE 0
133 
134 
143 
148 
153 };
154 
155 
164 
169 
174 };
175 
176 
190 };
191 
192 
200  uint8_t version;
201 
206 
207  /* followed by supported authentication methods, 1 byte per method */
208 };
209 
210 
218  uint8_t version;
219 
224  uint8_t auth_method;
225 };
226 
227 
235  uint8_t version;
236 
240  uint8_t command;
241 
245  uint8_t resvd;
246 
250  uint8_t addr_type;
251 
252  /*
253  * Followed by either an ip4/ipv6 address or a domain name with a
254  * length field (uint8_t) in front (depending on @e addr_type).
255  * followed by port number in network byte order (uint16_t).
256  */
257 };
258 
259 
267  uint8_t version;
268 
272  uint8_t reply;
273 
277  uint8_t reserved;
278 
282  uint8_t addr_type;
283 
284  /*
285  * Followed by either an ip4/ipv6 address or a domain name with a
286  * length field (uint8_t) in front (depending on @e addr_type).
287  * followed by port number in network byte order (uint16_t).
288  */
289 };
290 
291 
292 
293 /* *********************** Datastructures for HTTP handling ****************** */
294 
298 struct ProxyCA {
302  gnutls_x509_crt_t cert;
303 
307  gnutls_x509_privkey_t key;
308 };
309 
310 
318  char cert[MAX_PEM_SIZE];
319 
324 };
325 
326 
327 
331 struct MhdHttpList {
335  struct MhdHttpList *prev;
336 
340  struct MhdHttpList *next;
341 
345  char *domain;
346 
350  struct MHD_Daemon *daemon;
351 
356 
361 
365  int is_ssl;
366 };
367 
368 
369 /* ***************** Datastructures for Socks handling **************** */
370 
371 
380 
385 
390 
395 
400 
405 
410 
415 
420 
425 };
426 
427 
436 
441 
445  char *type;
446 
450  char *value;
451 };
452 
461 
466 
471 
476 
481 
486 
491 
495  char rbuf[SOCKS_BUFFERSIZE];
496 
500  char wbuf[SOCKS_BUFFERSIZE];
501 
505  char io_buf[IO_BUFFERSIZE];
506 
510  struct MhdHttpList *hd;
511 
515  struct MHD_Connection *con;
516 
520  struct MHD_Response *response;
521 
525  char *domain;
526 
530  char *leho;
531 
535  char *dane_data[MAX_DANES + 1];
536 
540  char *url;
541 
545  CURL *curl;
546 
550  struct curl_slist *headers;
551 
555  struct curl_slist *hosts;
556 
560  unsigned int response_code;
561 
565  int dane_data_len[MAX_DANES + 1];
566 
571  unsigned int num_danes;
572 
576  size_t rbuf_len;
577 
581  size_t wbuf_len;
582 
586  size_t io_len;
587 
591  struct sockaddr_storage destination_address;
592 
597 
601  uint16_t port;
602 
607 
612 
617 
621  int is_gns;
622 
626  int is_tls;
627 
632 
637 };
638 
639 
640 
641 /* *********************** Globals **************************** */
642 
646 static in_addr_t address;
647 
651 static struct in6_addr address6;
652 
656 static uint16_t port = GNUNET_GNS_PROXY_PORT;
657 
661 static char *cafile_opt;
662 
667 
672 
677 
682 
687 
691 static CURLM *curl_multi;
692 
697 
701 static int disable_v6;
702 
707 
712 
717 static struct MhdHttpList *httpd;
718 
722 static struct Socks5Request *s5r_head;
723 
727 static struct Socks5Request *s5r_tail;
728 
732 static struct ProxyCA proxy_ca;
733 
737 static struct MHD_Response *curl_failure_response;
738 
742 static const struct GNUNET_CONFIGURATION_Handle *cfg;
743 
744 
745 /* ************************* Global helpers ********************* */
746 
747 
753 static void
754 run_mhd_now(struct MhdHttpList *hd);
755 
756 
762 static void
764 {
766  "Cleaning up socks request\n");
767  if (NULL != s5r->curl)
768  {
770  "Cleaning up cURL handle\n");
771  curl_multi_remove_handle(curl_multi,
772  s5r->curl);
773  curl_easy_cleanup(s5r->curl);
774  s5r->curl = NULL;
775  }
776  if (s5r->suspended)
777  {
778  s5r->suspended = GNUNET_NO;
779  MHD_resume_connection(s5r->con);
780  }
781  curl_slist_free_all(s5r->headers);
782  if (NULL != s5r->hosts)
783  {
784  curl_slist_free_all(s5r->hosts);
785  }
786  if ((NULL != s5r->response) &&
788  {
789  MHD_destroy_response(s5r->response);
790  s5r->response = NULL;
791  }
792  if (NULL != s5r->rtask)
793  {
795  s5r->rtask = NULL;
796  }
797  if (NULL != s5r->timeout_task)
798  {
800  s5r->timeout_task = NULL;
801  }
802  if (NULL != s5r->wtask)
803  {
805  s5r->wtask = NULL;
806  }
807  if (NULL != s5r->gns_lookup)
808  {
810  s5r->gns_lookup = NULL;
811  }
812  if (NULL != s5r->sock)
813  {
814  if (SOCKS5_SOCKET_WITH_MHD <= s5r->state)
816  else
818  s5r->sock = NULL;
819  }
821  s5r_tail,
822  s5r);
826  for (unsigned int i = 0; i < s5r->num_danes; i++)
827  GNUNET_free(s5r->dane_data[i]);
828  GNUNET_free(s5r);
829 }
830 
831 
832 /* ************************* HTTP handling with cURL *********************** */
833 
834 static void
836 
837 
849 static ssize_t
850 mhd_content_cb(void *cls,
851  uint64_t pos,
852  char* buf,
853  size_t max)
854 {
855  struct Socks5Request *s5r = cls;
856  size_t bytes_to_copy;
857 
858  if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
860  {
861  /* we're still not done with the upload, do not yet
862  start the download, the IO buffer is still full
863  with upload data. */
865  "Pausing MHD download %s%s, not yet ready for download\n",
866  s5r->domain,
867  s5r->url);
868  return 0; /* not yet ready for data download */
869  }
870  bytes_to_copy = GNUNET_MIN(max,
871  s5r->io_len);
872  if ((0 == bytes_to_copy) &&
874  {
876  "Pausing MHD download %s%s, no data available\n",
877  s5r->domain,
878  s5r->url);
879  if (NULL != s5r->curl)
880  {
882  "Continuing CURL interaction for %s%s\n",
883  s5r->domain,
884  s5r->url);
885  if (GNUNET_YES == s5r->curl_paused)
886  {
887  s5r->curl_paused = GNUNET_NO;
888  curl_easy_pause(s5r->curl,
889  CURLPAUSE_CONT);
890  }
892  }
893  if (GNUNET_NO == s5r->suspended)
894  {
895  MHD_suspend_connection(s5r->con);
896  s5r->suspended = GNUNET_YES;
897  }
898  return 0; /* more data later */
899  }
900  if ((0 == bytes_to_copy) &&
902  {
904  "Completed MHD download %s%s\n",
905  s5r->domain,
906  s5r->url);
907  return MHD_CONTENT_READER_END_OF_STREAM;
908  }
910  "Writing %llu/%llu bytes to %s%s\n",
911  (unsigned long long)bytes_to_copy,
912  (unsigned long long)s5r->io_len,
913  s5r->domain,
914  s5r->url);
915  GNUNET_memcpy(buf,
916  s5r->io_buf,
917  bytes_to_copy);
918  memmove(s5r->io_buf,
919  &s5r->io_buf[bytes_to_copy],
920  s5r->io_len - bytes_to_copy);
921  s5r->io_len -= bytes_to_copy;
922  if ((NULL != s5r->curl) &&
923  (GNUNET_YES == s5r->curl_paused))
924  {
926  "Continuing CURL interaction for %s%s\n",
927  s5r->domain,
928  s5r->url);
929  s5r->curl_paused = GNUNET_NO;
930  curl_easy_pause(s5r->curl,
931  CURLPAUSE_CONT);
932  }
933  return bytes_to_copy;
934 }
935 
936 
945 static int
947 {
948  unsigned int cert_list_size;
949  const gnutls_datum_t *chainp;
950  const struct curl_tlssessioninfo *tlsinfo;
951  char certdn[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 3];
952  size_t size;
953  gnutls_x509_crt_t x509_cert;
954  int rc;
955  const char *name;
956 
957  s5r->ssl_checked = GNUNET_YES;
959  "Checking X.509 certificate\n");
960  if (CURLE_OK !=
961  curl_easy_getinfo(s5r->curl,
962  CURLINFO_TLS_SESSION,
963  &tlsinfo))
964  return GNUNET_SYSERR;
965  if (CURLSSLBACKEND_GNUTLS != tlsinfo->backend)
966  {
968  _("Unsupported CURL TLS backend %d\n"),
969  tlsinfo->backend);
970  return GNUNET_SYSERR;
971  }
972  chainp = gnutls_certificate_get_peers(tlsinfo->internals,
973  &cert_list_size);
974  if ((!chainp) ||
975  (0 == cert_list_size))
976  return GNUNET_SYSERR;
977 
978  size = sizeof(certdn);
979  /* initialize an X.509 certificate structure. */
980  gnutls_x509_crt_init(&x509_cert);
981  gnutls_x509_crt_import(x509_cert,
982  chainp,
983  GNUTLS_X509_FMT_DER);
984 
985  if (0 != (rc = gnutls_x509_crt_get_dn_by_oid(x509_cert,
986  GNUTLS_OID_X520_COMMON_NAME,
987  0, /* the first and only one */
988  0 /* no DER encoding */,
989  certdn,
990  &size)))
991  {
993  _("Failed to fetch CN from cert: %s\n"),
994  gnutls_strerror(rc));
995  gnutls_x509_crt_deinit(x509_cert);
996  return GNUNET_SYSERR;
997  }
998  /* check for TLSA/DANE records */
999 #if HAVE_GNUTLS_DANE
1000  if (0 != s5r->num_danes)
1001  {
1002  dane_state_t dane_state;
1003  dane_query_t dane_query;
1004  unsigned int verify;
1005 
1006  /* FIXME: add flags to gnutls to NOT read UNBOUND_ROOT_KEY_FILE here! */
1007  if (0 != (rc = dane_state_init(&dane_state,
1008 #ifdef DANE_F_IGNORE_DNSSEC
1009  DANE_F_IGNORE_DNSSEC |
1010 #endif
1011  DANE_F_IGNORE_LOCAL_RESOLVER)))
1012  {
1014  _("Failed to initialize DANE: %s\n"),
1015  dane_strerror(rc));
1016  gnutls_x509_crt_deinit(x509_cert);
1017  return GNUNET_SYSERR;
1018  }
1019  s5r->dane_data[s5r->num_danes] = NULL;
1020  s5r->dane_data_len[s5r->num_danes] = 0;
1021  if (0 != (rc = dane_raw_tlsa(dane_state,
1022  &dane_query,
1023  s5r->dane_data,
1024  s5r->dane_data_len,
1025  GNUNET_YES,
1026  GNUNET_NO)))
1027  {
1029  _("Failed to parse DANE record: %s\n"),
1030  dane_strerror(rc));
1031  dane_state_deinit(dane_state);
1032  gnutls_x509_crt_deinit(x509_cert);
1033  return GNUNET_SYSERR;
1034  }
1035  if (0 != (rc = dane_verify_crt_raw(dane_state,
1036  chainp,
1037  cert_list_size,
1038  gnutls_certificate_type_get(tlsinfo->internals),
1039  dane_query,
1040  0, 0,
1041  &verify)))
1042  {
1044  _("Failed to verify TLS connection using DANE: %s\n"),
1045  dane_strerror(rc));
1046  dane_query_deinit(dane_query);
1047  dane_state_deinit(dane_state);
1048  gnutls_x509_crt_deinit(x509_cert);
1049  return GNUNET_SYSERR;
1050  }
1051  if (0 != verify)
1052  {
1054  _("Failed DANE verification failed with GnuTLS verify status code: %u\n"),
1055  verify);
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  dane_query_deinit(dane_query);
1062  dane_state_deinit(dane_state);
1063  /* success! */
1064  }
1065  else
1066 #endif
1067  {
1068  /* try LEHO or ordinary domain name X509 verification */
1069  name = s5r->domain;
1070  if (NULL != s5r->leho)
1071  name = s5r->leho;
1072  if (NULL != name)
1073  {
1074  if (0 == (rc = gnutls_x509_crt_check_hostname(x509_cert,
1075  name)))
1076  {
1078  _("TLS certificate subject name (%s) does not match `%s': %d\n"),
1079  certdn,
1080  name,
1081  rc);
1082  gnutls_x509_crt_deinit(x509_cert);
1083  return GNUNET_SYSERR;
1084  }
1085  }
1086  else
1087  {
1088  /* we did not even have the domain name!? */
1089  GNUNET_break(0);
1090  return GNUNET_SYSERR;
1091  }
1092  }
1093  gnutls_x509_crt_deinit(x509_cert);
1094  return GNUNET_OK;
1095 }
1096 
1097 
1110 static size_t
1111 curl_check_hdr(void *buffer,
1112  size_t size,
1113  size_t nmemb,
1114  void *cls)
1115 {
1116  struct Socks5Request *s5r = cls;
1117  struct HttpResponseHeader *header;
1118  size_t bytes = size * nmemb;
1119  char *ndup;
1120  const char *hdr_type;
1121  const char *cookie_domain;
1122  char *hdr_val;
1123  char *new_cookie_hdr;
1124  char *new_location;
1125  size_t offset;
1126  size_t delta_cdomain;
1127  int domain_matched;
1128  char *tok;
1129 
1131  "Receiving HTTP response header from CURL\n");
1132  /* first, check TLS certificate */
1133  if ((GNUNET_YES != s5r->ssl_checked) &&
1134  (GNUNET_YES == s5r->is_tls))
1135  //(HTTPS_PORT == s5r->port))
1136  {
1137  if (GNUNET_OK != check_ssl_certificate(s5r))
1138  return 0;
1139  }
1140  ndup = GNUNET_strndup(buffer,
1141  bytes);
1142  hdr_type = strtok(ndup,
1143  ":");
1144  if (NULL == hdr_type)
1145  {
1146  GNUNET_free(ndup);
1147  return bytes;
1148  }
1149  hdr_val = strtok(NULL,
1150  "");
1151  if (NULL == hdr_val)
1152  {
1153  GNUNET_free(ndup);
1154  return bytes;
1155  }
1156  if (' ' == *hdr_val)
1157  hdr_val++;
1158 
1159  /* custom logic for certain header types */
1160  new_cookie_hdr = NULL;
1161  if ((NULL != s5r->leho) &&
1162  (0 == strcasecmp(hdr_type,
1163  MHD_HTTP_HEADER_SET_COOKIE)))
1164 
1165  {
1166  new_cookie_hdr = GNUNET_malloc(strlen(hdr_val) +
1167  strlen(s5r->domain) + 1);
1168  offset = 0;
1169  domain_matched = GNUNET_NO; /* make sure we match domain at most once */
1170  for (tok = strtok(hdr_val, ";"); NULL != tok; tok = strtok(NULL, ";"))
1171  {
1172  if ((0 == strncasecmp(tok,
1173  " domain",
1174  strlen(" domain"))) &&
1175  (GNUNET_NO == domain_matched))
1176  {
1177  domain_matched = GNUNET_YES;
1178  cookie_domain = tok + strlen(" domain") + 1;
1179  if (strlen(cookie_domain) < strlen(s5r->leho))
1180  {
1181  delta_cdomain = strlen(s5r->leho) - strlen(cookie_domain);
1182  if (0 == strcasecmp(cookie_domain,
1183  s5r->leho + delta_cdomain))
1184  {
1185  offset += sprintf(new_cookie_hdr + offset,
1186  " domain=%s;",
1187  s5r->domain);
1188  continue;
1189  }
1190  }
1191  else if (0 == strcmp(cookie_domain,
1192  s5r->leho))
1193  {
1194  offset += sprintf(new_cookie_hdr + offset,
1195  " domain=%s;",
1196  s5r->domain);
1197  continue;
1198  }
1199  else if (('.' == cookie_domain[0]) &&
1200  (0 == strcmp(&cookie_domain[1],
1201  s5r->leho)))
1202  {
1203  offset += sprintf(new_cookie_hdr + offset,
1204  " domain=.%s;",
1205  s5r->domain);
1206  continue;
1207  }
1209  _("Cookie domain `%s' supplied by server is invalid\n"),
1210  tok);
1211  }
1212  GNUNET_memcpy(new_cookie_hdr + offset,
1213  tok,
1214  strlen(tok));
1215  offset += strlen(tok);
1216  new_cookie_hdr[offset++] = ';';
1217  }
1218  hdr_val = new_cookie_hdr;
1219  }
1220 
1221  new_location = NULL;
1222  if (0 == strcasecmp(MHD_HTTP_HEADER_TRANSFER_ENCODING,
1223  hdr_type))
1224  {
1225  /* Ignore transfer encoding, set automatically by MHD if required */
1226  goto cleanup;
1227  }
1228  if ((0 == strcasecmp(MHD_HTTP_HEADER_LOCATION,
1229  hdr_type)))
1230  {
1231  char *leho_host;
1232 
1233  GNUNET_asprintf(&leho_host,
1234  (GNUNET_YES != s5r->is_tls) //(HTTPS_PORT != s5r->port)
1235  ? "http://%s"
1236  : "https://%s",
1237  s5r->leho);
1238  if (0 == strncmp(leho_host,
1239  hdr_val,
1240  strlen(leho_host)))
1241  {
1242  GNUNET_asprintf(&new_location,
1243  "%s%s%s",
1244  (GNUNET_YES != s5r->is_tls) //(HTTPS_PORT != s5r->port)
1245  ? "http://"
1246  : "https://",
1247  s5r->domain,
1248  hdr_val + strlen(leho_host));
1249  hdr_val = new_location;
1250  }
1251  GNUNET_free(leho_host);
1252  }
1253  if (0 == strcasecmp(MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
1254  hdr_type))
1255  {
1256  char *leho_host;
1257 
1258  GNUNET_asprintf(&leho_host,
1259  (GNUNET_YES != s5r->is_tls) //(HTTPS_PORT != s5r->port)
1260  ? "http://%s"
1261  : "https://%s",
1262  s5r->leho);
1263  if (0 == strncmp(leho_host,
1264  hdr_val,
1265  strlen(leho_host)))
1266  {
1267  GNUNET_asprintf(&new_location,
1268  "%s%s",
1269  (GNUNET_YES != s5r->is_tls) //(HTTPS_PORT != s5r->port)
1270  ? "http://"
1271  : "https://",
1272  s5r->domain);
1273  hdr_val = new_location;
1274  }
1275  GNUNET_free(leho_host);
1276  }
1277 
1278  /* MHD does not allow certain characters in values, remove those */
1279  if (NULL != (tok = strchr(hdr_val, '\n')))
1280  *tok = '\0';
1281  if (NULL != (tok = strchr(hdr_val, '\r')))
1282  *tok = '\0';
1283  if (NULL != (tok = strchr(hdr_val, '\t')))
1284  *tok = '\0';
1285  if (0 != strlen(hdr_val)) /* Rely in MHD to set those */
1286  {
1288  "Adding header %s: %s to MHD response\n",
1289  hdr_type,
1290  hdr_val);
1291  header = GNUNET_new(struct HttpResponseHeader);
1292  header->type = GNUNET_strdup(hdr_type);
1293  header->value = GNUNET_strdup(hdr_val);
1295  s5r->header_tail,
1296  header);
1297  }
1298 cleanup:
1299  GNUNET_free(ndup);
1300  GNUNET_free_non_null(new_cookie_hdr);
1301  GNUNET_free_non_null(new_location);
1302  return bytes;
1303 }
1304 
1305 
1314 static int
1316 {
1317  long resp_code;
1318  double content_length;
1319 
1320  if (NULL != s5r->response)
1321  {
1323  "Response already set!\n");
1324  return GNUNET_SYSERR;
1325  }
1326 
1327  GNUNET_break(CURLE_OK ==
1328  curl_easy_getinfo(s5r->curl,
1329  CURLINFO_RESPONSE_CODE,
1330  &resp_code));
1331  GNUNET_break(CURLE_OK ==
1332  curl_easy_getinfo(s5r->curl,
1333  CURLINFO_CONTENT_LENGTH_DOWNLOAD,
1334  &content_length));
1336  "Creating MHD response with code %d and size %d for %s%s\n",
1337  (int)resp_code,
1338  (int)content_length,
1339  s5r->domain,
1340  s5r->url);
1341  s5r->response_code = resp_code;
1342  s5r->response = MHD_create_response_from_callback((-1 == content_length)
1343  ? MHD_SIZE_UNKNOWN
1344  : content_length,
1345  IO_BUFFERSIZE,
1346  &mhd_content_cb,
1347  s5r,
1348  NULL);
1349  for (struct HttpResponseHeader *header = s5r->header_head;
1350  NULL != header;
1351  header = header->next)
1352  {
1353  if (0 == strcasecmp(header->type,
1354  MHD_HTTP_HEADER_CONTENT_LENGTH))
1355  continue; /* MHD won't let us mess with those, for good reason */
1356  if ((0 == strcasecmp(header->type,
1357  MHD_HTTP_HEADER_TRANSFER_ENCODING)) &&
1358  ((0 == strcasecmp(header->value,
1359  "identity")) ||
1360  (0 == strcasecmp(header->value,
1361  "chunked"))))
1362  continue; /* MHD won't let us mess with those, for good reason */
1363  if (MHD_YES !=
1364  MHD_add_response_header(s5r->response,
1365  header->type,
1366  header->value))
1367  {
1368  GNUNET_break(0);
1370  "Failed to add header `%s:%s'\n",
1371  header->type,
1372  header->value);
1373  }
1374  }
1375  /* force connection to be closed after each request, as we
1376  do not support HTTP pipelining (yet, FIXME!) */
1377  /*GNUNET_break (MHD_YES ==
1378  MHD_add_response_header (s5r->response,
1379  MHD_HTTP_HEADER_CONNECTION,
1380  "close"));*/
1381  MHD_resume_connection(s5r->con);
1382  s5r->suspended = GNUNET_NO;
1383  return GNUNET_OK;
1384 }
1385 
1386 
1397 static size_t
1399  size_t size,
1400  size_t nmemb,
1401  void* ctx)
1402 {
1403  struct Socks5Request *s5r = ctx;
1404  size_t total = size * nmemb;
1405 
1407  "Receiving %ux%u bytes for `%s%s' from cURL to download\n",
1408  (unsigned int)size,
1409  (unsigned int)nmemb,
1410  s5r->domain,
1411  s5r->url);
1412  if (NULL == s5r->response)
1415  if ((SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) &&
1416  (0 == s5r->io_len))
1417  {
1419  "Previous upload finished... starting DOWNLOAD.\n");
1421  }
1422  if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
1423  (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1424  {
1425  /* we're still not done with the upload, do not yet
1426  start the download, the IO buffer is still full
1427  with upload data. */
1429  "Pausing CURL download `%s%s', waiting for UPLOAD to finish\n",
1430  s5r->domain,
1431  s5r->url);
1432  s5r->curl_paused = GNUNET_YES;
1433  return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */
1434  }
1435  if (sizeof(s5r->io_buf) - s5r->io_len < total)
1436  {
1438  "Pausing CURL `%s%s' download, not enough space %llu %llu %llu\n",
1439  s5r->domain,
1440  s5r->url,
1441  (unsigned long long)sizeof(s5r->io_buf),
1442  (unsigned long long)s5r->io_len,
1443  (unsigned long long)total);
1444  s5r->curl_paused = GNUNET_YES;
1445  return CURL_WRITEFUNC_PAUSE; /* not enough space */
1446  }
1447  GNUNET_memcpy(&s5r->io_buf[s5r->io_len],
1448  ptr,
1449  total);
1450  s5r->io_len += total;
1451  if (GNUNET_YES == s5r->suspended)
1452  {
1453  MHD_resume_connection(s5r->con);
1454  s5r->suspended = GNUNET_NO;
1455  }
1457  "Received %llu bytes of payload via cURL from %s\n",
1458  (unsigned long long)total,
1459  s5r->domain);
1460  if (s5r->io_len == total)
1461  run_mhd_now(s5r->hd);
1462  return total;
1463 }
1464 
1465 
1476 static size_t
1478  size_t size,
1479  size_t nmemb,
1480  void *cls)
1481 {
1482  struct Socks5Request *s5r = cls;
1483  size_t len = size * nmemb;
1484  size_t to_copy;
1485 
1487  "Receiving %ux%u bytes for `%s%s' from cURL to upload\n",
1488  (unsigned int)size,
1489  (unsigned int)nmemb,
1490  s5r->domain,
1491  s5r->url);
1492 
1493  if ((0 == s5r->io_len) &&
1494  (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1495  {
1497  "Pausing CURL UPLOAD %s%s, need more data\n",
1498  s5r->domain,
1499  s5r->url);
1500  return CURL_READFUNC_PAUSE;
1501  }
1502  if ((0 == s5r->io_len) &&
1503  (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1504  {
1506  if (GNUNET_YES == s5r->curl_paused)
1507  {
1508  s5r->curl_paused = GNUNET_NO;
1509  curl_easy_pause(s5r->curl,
1510  CURLPAUSE_CONT);
1511  }
1513  "Completed CURL UPLOAD %s%s\n",
1514  s5r->domain,
1515  s5r->url);
1516  return 0; /* upload finished, can now download */
1517  }
1518  if ((SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) &&
1519  (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1520  {
1521  GNUNET_break(0);
1522  return CURL_READFUNC_ABORT;
1523  }
1524  to_copy = GNUNET_MIN(s5r->io_len,
1525  len);
1526  GNUNET_memcpy(buf,
1527  s5r->io_buf,
1528  to_copy);
1529  memmove(s5r->io_buf,
1530  &s5r->io_buf[to_copy],
1531  s5r->io_len - to_copy);
1532  s5r->io_len -= to_copy;
1533  if (s5r->io_len + to_copy == sizeof(s5r->io_buf))
1534  run_mhd_now(s5r->hd); /* got more space for upload now */
1535  return to_copy;
1536 }
1537 
1538 
1539 /* ************************** main loop of cURL interaction ****************** */
1540 
1541 
1548 static void
1549 curl_task_download(void *cls);
1550 
1551 
1555 static void
1557 {
1558  CURLMcode mret;
1559  fd_set rs;
1560  fd_set ws;
1561  fd_set es;
1562  int max;
1563  struct GNUNET_NETWORK_FDSet *grs;
1564  struct GNUNET_NETWORK_FDSet *gws;
1565  long to;
1566  struct GNUNET_TIME_Relative rtime;
1567 
1569  "Scheduling CURL interaction\n");
1570  if (NULL != curl_download_task)
1571  {
1572  GNUNET_SCHEDULER_cancel(curl_download_task);
1573  curl_download_task = NULL;
1574  }
1575  max = -1;
1576  FD_ZERO(&rs);
1577  FD_ZERO(&ws);
1578  FD_ZERO(&es);
1579  if (CURLM_OK != (mret = curl_multi_fdset(curl_multi,
1580  &rs,
1581  &ws,
1582  &es,
1583  &max)))
1584  {
1586  "%s failed at %s:%d: `%s'\n",
1587  "curl_multi_fdset", __FILE__, __LINE__,
1588  curl_multi_strerror(mret));
1589  return;
1590  }
1591  to = -1;
1592  GNUNET_break(CURLM_OK ==
1593  curl_multi_timeout(curl_multi,
1594  &to));
1595  if (-1 == to)
1597  else
1599  to);
1600  if (-1 != max)
1601  {
1605  &rs,
1606  max + 1);
1608  &ws,
1609  max + 1);
1611  rtime,
1612  grs,
1613  gws,
1615  curl_multi);
1618  }
1619  else
1620  {
1621  curl_download_task = GNUNET_SCHEDULER_add_delayed(rtime,
1623  curl_multi);
1624  }
1625 }
1626 
1627 
1633 static void
1635 {
1636  int running;
1637  int msgnum;
1638  struct CURLMsg *msg;
1639  CURLMcode mret;
1640  struct Socks5Request *s5r;
1641 
1642  curl_download_task = NULL;
1644  "Running CURL interaction\n");
1645  do
1646  {
1647  running = 0;
1648  mret = curl_multi_perform(curl_multi,
1649  &running);
1651  "Checking CURL multi status: %d\n",
1652  mret);
1653  while (NULL != (msg = curl_multi_info_read(curl_multi,
1654  &msgnum)))
1655  {
1656  GNUNET_break(CURLE_OK ==
1657  curl_easy_getinfo(msg->easy_handle,
1658  CURLINFO_PRIVATE,
1659  (char **)&s5r));
1660  if (NULL == s5r)
1661  {
1662  GNUNET_break(0);
1663  continue;
1664  }
1665  switch (msg->msg)
1666  {
1667  case CURLMSG_NONE:
1668  /* documentation says this is not used */
1669  GNUNET_break(0);
1670  break;
1671 
1672  case CURLMSG_DONE:
1673  switch (msg->data.result)
1674  {
1675  case CURLE_OK:
1676  case CURLE_GOT_NOTHING:
1678  "CURL download %s%s completed.\n",
1679  s5r->domain,
1680  s5r->url);
1681  if (NULL == s5r->response)
1682  {
1685  }
1686  s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE;
1687  if (GNUNET_YES == s5r->suspended)
1688  {
1689  MHD_resume_connection(s5r->con);
1690  s5r->suspended = GNUNET_NO;
1691  }
1692  run_mhd_now(s5r->hd);
1693  break;
1694 
1695  default:
1697  "Download curl %s%s failed: %s\n",
1698  s5r->domain,
1699  s5r->url,
1700  curl_easy_strerror(msg->data.result));
1701  /* FIXME: indicate error somehow? close MHD connection badly as well? */
1702  s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE;
1703  if (GNUNET_YES == s5r->suspended)
1704  {
1705  MHD_resume_connection(s5r->con);
1706  s5r->suspended = GNUNET_NO;
1707  }
1708  run_mhd_now(s5r->hd);
1709  break;
1710  }
1711  if (NULL == s5r->response)
1712  s5r->response = curl_failure_response;
1713  break;
1714 
1715  case CURLMSG_LAST:
1716  /* documentation says this is not used */
1717  GNUNET_break(0);
1718  break;
1719 
1720  default:
1721  /* unexpected status code */
1722  GNUNET_break(0);
1723  break;
1724  }
1725  }
1726  ;
1727  }
1728  while (mret == CURLM_CALL_MULTI_PERFORM);
1729  if (CURLM_OK != mret)
1731  "%s failed at %s:%d: `%s'\n",
1732  "curl_multi_perform", __FILE__, __LINE__,
1733  curl_multi_strerror(mret));
1734  if (0 == running)
1735  {
1737  "Suspending cURL multi loop, no more events pending\n");
1738  if (NULL != curl_download_task)
1739  {
1740  GNUNET_SCHEDULER_cancel(curl_download_task);
1741  curl_download_task = NULL;
1742  }
1743  return; /* nothing more in progress */
1744  }
1746 }
1747 
1748 
1749 /* ********************************* MHD response generation ******************* */
1750 
1751 
1765 static int
1766 con_val_iter(void *cls,
1767  enum MHD_ValueKind kind,
1768  const char *key,
1769  const char *value)
1770 {
1771  struct Socks5Request *s5r = cls;
1772  char *hdr;
1773 
1774  if ((0 == strcasecmp(MHD_HTTP_HEADER_HOST,
1775  key)) &&
1776  (NULL != s5r->leho))
1777  value = s5r->leho;
1778  GNUNET_asprintf(&hdr,
1779  "%s: %s",
1780  key,
1781  value);
1783  "Adding HEADER `%s' to HTTP request\n",
1784  hdr);
1785  s5r->headers = curl_slist_append(s5r->headers,
1786  hdr);
1787  GNUNET_free(hdr);
1788  return MHD_YES;
1789 }
1790 
1791 
1815 static int
1817  struct MHD_Connection *con,
1818  const char *url,
1819  const char *meth,
1820  const char *ver,
1821  const char *upload_data,
1822  size_t *upload_data_size,
1823  void **con_cls)
1824 {
1825  struct Socks5Request *s5r = *con_cls;
1826  char *curlurl;
1827  char ipstring[INET6_ADDRSTRLEN];
1828  char ipaddr[INET6_ADDRSTRLEN + 2];
1829  const struct sockaddr *sa;
1830  const struct sockaddr_in *s4;
1831  const struct sockaddr_in6 *s6;
1832  uint16_t port;
1833  size_t left;
1834 
1835  if (NULL == s5r)
1836  {
1837  GNUNET_break(0);
1838  return MHD_NO;
1839  }
1840  s5r->con = con;
1841  /* Fresh connection. */
1842  if (SOCKS5_SOCKET_WITH_MHD == s5r->state)
1843  {
1844  /* first time here, initialize curl handle */
1845  if (s5r->is_gns)
1846  {
1847  sa = (const struct sockaddr *)&s5r->destination_address;
1848  switch (sa->sa_family)
1849  {
1850  case AF_INET:
1851  s4 = (const struct sockaddr_in *)&s5r->destination_address;
1852  if (NULL == inet_ntop(AF_INET,
1853  &s4->sin_addr,
1854  ipstring,
1855  sizeof(ipstring)))
1856  {
1857  GNUNET_break(0);
1858  return MHD_NO;
1859  }
1860  GNUNET_snprintf(ipaddr,
1861  sizeof(ipaddr),
1862  "%s",
1863  ipstring);
1864  port = ntohs(s4->sin_port);
1865  break;
1866 
1867  case AF_INET6:
1868  s6 = (const struct sockaddr_in6 *)&s5r->destination_address;
1869  if (NULL == inet_ntop(AF_INET6,
1870  &s6->sin6_addr,
1871  ipstring,
1872  sizeof(ipstring)))
1873  {
1874  GNUNET_break(0);
1875  return MHD_NO;
1876  }
1877  GNUNET_snprintf(ipaddr,
1878  sizeof(ipaddr),
1879  "%s",
1880  ipstring);
1881  port = ntohs(s6->sin6_port);
1882  break;
1883 
1884  default:
1885  GNUNET_break(0);
1886  return MHD_NO;
1887  }
1888  }
1889  else
1890  {
1891  port = s5r->port;
1892  }
1893  if (NULL == s5r->curl)
1894  s5r->curl = curl_easy_init();
1895  if (NULL == s5r->curl)
1896  return MHD_queue_response(con,
1897  MHD_HTTP_INTERNAL_SERVER_ERROR,
1899  curl_easy_setopt(s5r->curl,
1900  CURLOPT_HEADERFUNCTION,
1901  &curl_check_hdr);
1902  curl_easy_setopt(s5r->curl,
1903  CURLOPT_HEADERDATA,
1904  s5r);
1905  curl_easy_setopt(s5r->curl,
1906  CURLOPT_FOLLOWLOCATION,
1907  0);
1908  if (s5r->is_gns)
1909  curl_easy_setopt(s5r->curl,
1910  CURLOPT_IPRESOLVE,
1911  CURL_IPRESOLVE_V4);
1912  curl_easy_setopt(s5r->curl,
1913  CURLOPT_CONNECTTIMEOUT,
1914  600L);
1915  curl_easy_setopt(s5r->curl,
1916  CURLOPT_TIMEOUT,
1917  600L);
1918  curl_easy_setopt(s5r->curl,
1919  CURLOPT_NOSIGNAL,
1920  1L);
1921  curl_easy_setopt(s5r->curl,
1922  CURLOPT_HTTP_CONTENT_DECODING,
1923  0);
1924  curl_easy_setopt(s5r->curl,
1925  CURLOPT_NOSIGNAL,
1926  1L);
1927  curl_easy_setopt(s5r->curl,
1928  CURLOPT_PRIVATE,
1929  s5r);
1930  curl_easy_setopt(s5r->curl,
1931  CURLOPT_VERBOSE,
1932  0L);
1938  if (NULL != s5r->leho)
1939  {
1940  char *curl_hosts;
1941 
1942  GNUNET_asprintf(&curl_hosts,
1943  "%s:%d:%s",
1944  s5r->leho,
1945  port,
1946  ipaddr);
1947  s5r->hosts = curl_slist_append(NULL,
1948  curl_hosts);
1949  curl_easy_setopt(s5r->curl,
1950  CURLOPT_RESOLVE,
1951  s5r->hosts);
1952  GNUNET_free(curl_hosts);
1953  }
1954  if (s5r->is_gns)
1955  {
1956  GNUNET_asprintf(&curlurl,
1957  (GNUNET_YES != s5r->is_tls) //(HTTPS_PORT != s5r->port)
1958  ? "http://%s:%d%s"
1959  : "https://%s:%d%s",
1960  (NULL != s5r->leho)
1961  ? s5r->leho
1962  : ipaddr,
1963  port,
1964  s5r->url);
1965  }
1966  else
1967  {
1968  GNUNET_asprintf(&curlurl,
1969  (GNUNET_YES != s5r->is_tls) //(HTTPS_PORT != s5r->port)
1970  ? "http://%s:%d%s"
1971  : "https://%s:%d%s",
1972  s5r->domain,
1973  port,
1974  s5r->url);
1975  }
1976  curl_easy_setopt(s5r->curl,
1977  CURLOPT_URL,
1978  curlurl);
1980  "Launching %s CURL interaction, fetching `%s'\n",
1981  (s5r->is_gns) ? "GNS" : "DNS",
1982  curlurl);
1983  GNUNET_free(curlurl);
1984  if (0 == strcasecmp(meth,
1985  MHD_HTTP_METHOD_PUT))
1986  {
1988  curl_easy_setopt(s5r->curl,
1989  CURLOPT_UPLOAD,
1990  1L);
1991  curl_easy_setopt(s5r->curl,
1992  CURLOPT_WRITEFUNCTION,
1993  &curl_download_cb);
1994  curl_easy_setopt(s5r->curl,
1995  CURLOPT_WRITEDATA,
1996  s5r);
1997  GNUNET_assert(CURLE_OK ==
1998  curl_easy_setopt(s5r->curl,
1999  CURLOPT_READFUNCTION,
2000  &curl_upload_cb));
2001  curl_easy_setopt(s5r->curl,
2002  CURLOPT_READDATA,
2003  s5r);
2004  {
2005  const char *us;
2006  long upload_size = 0;
2007 
2008  us = MHD_lookup_connection_value(con,
2009  MHD_HEADER_KIND,
2010  MHD_HTTP_HEADER_CONTENT_LENGTH);
2011  if ((1 == sscanf(us,
2012  "%ld",
2013  &upload_size)) &&
2014  (upload_size >= 0))
2015  {
2016  curl_easy_setopt(s5r->curl,
2017  CURLOPT_INFILESIZE,
2018  upload_size);
2019  }
2020  }
2021  }
2022  else if (0 == strcasecmp(meth, MHD_HTTP_METHOD_POST))
2023  {
2025  curl_easy_setopt(s5r->curl,
2026  CURLOPT_POST,
2027  1L);
2028  curl_easy_setopt(s5r->curl,
2029  CURLOPT_WRITEFUNCTION,
2030  &curl_download_cb);
2031  curl_easy_setopt(s5r->curl,
2032  CURLOPT_WRITEDATA,
2033  s5r);
2034  curl_easy_setopt(s5r->curl,
2035  CURLOPT_READFUNCTION,
2036  &curl_upload_cb);
2037  curl_easy_setopt(s5r->curl,
2038  CURLOPT_READDATA,
2039  s5r);
2040  {
2041  const char *us;
2042  long upload_size;
2043 
2044  upload_size = 0;
2045  us = MHD_lookup_connection_value(con,
2046  MHD_HEADER_KIND,
2047  MHD_HTTP_HEADER_CONTENT_LENGTH);
2048  if ((NULL != us) &&
2049  (1 == sscanf(us,
2050  "%ld",
2051  &upload_size)) &&
2052  (upload_size >= 0))
2053  {
2054  curl_easy_setopt(s5r->curl,
2055  CURLOPT_INFILESIZE,
2056  upload_size);
2057  }
2058  else
2059  {
2060  curl_easy_setopt(s5r->curl,
2061  CURLOPT_INFILESIZE,
2062  upload_size);
2063  }
2064  }
2065  }
2066  else if (0 == strcasecmp(meth,
2067  MHD_HTTP_METHOD_HEAD))
2068  {
2070  curl_easy_setopt(s5r->curl,
2071  CURLOPT_NOBODY,
2072  1L);
2073  }
2074  else if (0 == strcasecmp(meth,
2075  MHD_HTTP_METHOD_OPTIONS))
2076  {
2078  curl_easy_setopt(s5r->curl,
2079  CURLOPT_CUSTOMREQUEST,
2080  "OPTIONS");
2081  curl_easy_setopt(s5r->curl,
2082  CURLOPT_WRITEFUNCTION,
2083  &curl_download_cb);
2084  curl_easy_setopt(s5r->curl,
2085  CURLOPT_WRITEDATA,
2086  s5r);
2087  }
2088  else if (0 == strcasecmp(meth,
2089  MHD_HTTP_METHOD_GET))
2090  {
2092  curl_easy_setopt(s5r->curl,
2093  CURLOPT_HTTPGET,
2094  1L);
2095  curl_easy_setopt(s5r->curl,
2096  CURLOPT_WRITEFUNCTION,
2097  &curl_download_cb);
2098  curl_easy_setopt(s5r->curl,
2099  CURLOPT_WRITEDATA,
2100  s5r);
2101  }
2102  else if (0 == strcasecmp(meth,
2103  MHD_HTTP_METHOD_DELETE))
2104  {
2106  curl_easy_setopt(s5r->curl,
2107  CURLOPT_CUSTOMREQUEST,
2108  "DELETE");
2109  curl_easy_setopt(s5r->curl,
2110  CURLOPT_WRITEFUNCTION,
2111  &curl_download_cb);
2112  curl_easy_setopt(s5r->curl,
2113  CURLOPT_WRITEDATA,
2114  s5r);
2115  }
2116  else
2117  {
2119  _("Unsupported HTTP method `%s'\n"),
2120  meth);
2121  curl_easy_cleanup(s5r->curl);
2122  s5r->curl = NULL;
2123  return MHD_NO;
2124  }
2125 
2126  if (0 == strcasecmp(ver, MHD_HTTP_VERSION_1_0))
2127  {
2128  curl_easy_setopt(s5r->curl,
2129  CURLOPT_HTTP_VERSION,
2130  CURL_HTTP_VERSION_1_0);
2131  }
2132  else if (0 == strcasecmp(ver, MHD_HTTP_VERSION_1_1))
2133  {
2134  curl_easy_setopt(s5r->curl,
2135  CURLOPT_HTTP_VERSION,
2136  CURL_HTTP_VERSION_1_1);
2137  }
2138  else
2139  {
2140  curl_easy_setopt(s5r->curl,
2141  CURLOPT_HTTP_VERSION,
2142  CURL_HTTP_VERSION_NONE);
2143  }
2144 
2145  if (GNUNET_YES == s5r->is_tls) //(HTTPS_PORT == s5r->port)
2146  {
2147  curl_easy_setopt(s5r->curl,
2148  CURLOPT_USE_SSL,
2149  CURLUSESSL_ALL);
2150  if (0 < s5r->num_danes)
2151  curl_easy_setopt(s5r->curl,
2152  CURLOPT_SSL_VERIFYPEER,
2153  0L);
2154  else
2155  curl_easy_setopt(s5r->curl,
2156  CURLOPT_SSL_VERIFYPEER,
2157  1L);
2158  /* Disable cURL checking the hostname, as we will check ourselves
2159  as only we have the domain name or the LEHO or the DANE record */
2160  curl_easy_setopt(s5r->curl,
2161  CURLOPT_SSL_VERIFYHOST,
2162  0L);
2163  }
2164  else
2165  {
2166  curl_easy_setopt(s5r->curl,
2167  CURLOPT_USE_SSL,
2168  CURLUSESSL_NONE);
2169  }
2170 
2171  if (CURLM_OK !=
2172  curl_multi_add_handle(curl_multi,
2173  s5r->curl))
2174  {
2175  GNUNET_break(0);
2176  curl_easy_cleanup(s5r->curl);
2177  s5r->curl = NULL;
2178  return MHD_NO;
2179  }
2180  MHD_get_connection_values(con,
2181  MHD_HEADER_KIND,
2182  (MHD_KeyValueIterator) & con_val_iter,
2183  s5r);
2184  curl_easy_setopt(s5r->curl,
2185  CURLOPT_HTTPHEADER,
2186  s5r->headers);
2188  return MHD_YES;
2189  }
2190 
2191  /* continuing to process request */
2192  if (0 != *upload_data_size)
2193  {
2195  "Processing %u bytes UPLOAD\n",
2196  (unsigned int)*upload_data_size);
2197 
2198  /* FIXME: This must be set or a header with Transfer-Encoding: chunked. Else
2199  * upload callback is not called!
2200  */
2201  curl_easy_setopt(s5r->curl,
2202  CURLOPT_POSTFIELDSIZE,
2203  *upload_data_size);
2204 
2205  left = GNUNET_MIN(*upload_data_size,
2206  sizeof(s5r->io_buf) - s5r->io_len);
2207  GNUNET_memcpy(&s5r->io_buf[s5r->io_len],
2208  upload_data,
2209  left);
2210  s5r->io_len += left;
2211  *upload_data_size -= left;
2212  GNUNET_assert(NULL != s5r->curl);
2213  if (GNUNET_YES == s5r->curl_paused)
2214  {
2215  s5r->curl_paused = GNUNET_NO;
2216  curl_easy_pause(s5r->curl,
2217  CURLPAUSE_CONT);
2218  }
2219  return MHD_YES;
2220  }
2221  if (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state)
2222  {
2224  "Finished processing UPLOAD\n");
2226  }
2227  if (NULL == s5r->response)
2228  {
2230  "Waiting for HTTP response for %s%s...\n",
2231  s5r->domain,
2232  s5r->url);
2233  MHD_suspend_connection(con);
2234  s5r->suspended = GNUNET_YES;
2235  return MHD_YES;
2236  }
2238  "Queueing response for %s%s with MHD\n",
2239  s5r->domain,
2240  s5r->url);
2241  run_mhd_now(s5r->hd);
2242  return MHD_queue_response(con,
2243  s5r->response_code,
2244  s5r->response);
2245 }
2246 
2247 
2248 /* ******************** MHD HTTP setup and event loop ******************** */
2249 
2250 
2260 static void
2262  struct MHD_Connection *connection,
2263  void **con_cls,
2264  enum MHD_RequestTerminationCode toe)
2265 {
2266  struct Socks5Request *s5r = *con_cls;
2267 
2268  if (NULL == s5r)
2269  return;
2270  if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
2272  "MHD encountered error handling request: %d\n",
2273  toe);
2274  if (NULL != s5r->curl)
2275  {
2277  "Removing cURL handle (MHD interaction complete)\n");
2278  curl_multi_remove_handle(curl_multi,
2279  s5r->curl);
2280  curl_slist_free_all(s5r->headers);
2281  s5r->headers = NULL;
2282  curl_easy_reset(s5r->curl);
2283  s5r->rbuf_len = 0;
2284  s5r->wbuf_len = 0;
2285  s5r->io_len = 0;
2287  }
2288  if ((NULL != s5r->response) &&
2289  (curl_failure_response != s5r->response))
2290  MHD_destroy_response(s5r->response);
2291  for (struct HttpResponseHeader *header = s5r->header_head;
2292  NULL != header;
2293  header = s5r->header_head)
2294  {
2296  s5r->header_tail,
2297  header);
2298  GNUNET_free(header->type);
2299  GNUNET_free(header->value);
2300  GNUNET_free(header);
2301  }
2303  "Finished request for %s\n",
2304  s5r->url);
2305  GNUNET_free(s5r->url);
2307  s5r->url = NULL;
2308  s5r->response = NULL;
2309  *con_cls = NULL;
2310 }
2311 
2312 
2322 static void
2324  struct MHD_Connection *connection,
2325  void **con_cls,
2326  enum MHD_ConnectionNotificationCode cnc)
2327 {
2328  struct Socks5Request *s5r;
2329  const union MHD_ConnectionInfo *ci;
2330  int sock;
2331 
2332  switch (cnc)
2333  {
2334  case MHD_CONNECTION_NOTIFY_STARTED:
2335  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
2336  ci = MHD_get_connection_info(connection,
2337  MHD_CONNECTION_INFO_CONNECTION_FD);
2338  if (NULL == ci)
2339  {
2340  GNUNET_break(0);
2341  return;
2342  }
2343  sock = ci->connect_fd;
2344  for (s5r = s5r_head; NULL != s5r; s5r = s5r->next)
2345  {
2346  if (GNUNET_NETWORK_get_fd(s5r->sock) == sock)
2347  {
2349  "Context set...\n");
2350  s5r->ssl_checked = GNUNET_NO;
2351  *con_cls = s5r;
2352  break;
2353  }
2354  }
2355  break;
2356 
2357  case MHD_CONNECTION_NOTIFY_CLOSED:
2359  "Connection closed... cleaning up\n");
2360  s5r = *con_cls;
2361  if (NULL == s5r)
2362  {
2364  "Connection stale!\n");
2365  return;
2366  }
2367  cleanup_s5r(s5r);
2369  *con_cls = NULL;
2370  break;
2371 
2372  default:
2373  GNUNET_break(0);
2374  }
2375 }
2376 
2390 static void *
2392  const char *url,
2393  struct MHD_Connection *connection)
2394 {
2395  struct Socks5Request *s5r;
2396  const union MHD_ConnectionInfo *ci;
2397 
2398  ci = MHD_get_connection_info(connection,
2399  MHD_CONNECTION_INFO_SOCKET_CONTEXT);
2400  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
2401  if (NULL == ci)
2402  {
2403  GNUNET_break(0);
2404  return NULL;
2405  }
2406  s5r = ci->socket_context;
2407  if (NULL != s5r->url)
2408  {
2409  GNUNET_break(0);
2410  return NULL;
2411  }
2412  s5r->url = GNUNET_strdup(url);
2413  if (NULL != s5r->timeout_task)
2414  {
2416  s5r->timeout_task = NULL;
2417  }
2419  return s5r;
2420 }
2421 
2422 
2428 static void
2430 {
2431  GNUNET_CONTAINER_DLL_remove(mhd_httpd_head,
2432  mhd_httpd_tail,
2433  hd);
2435  MHD_stop_daemon(hd->daemon);
2436  if (NULL != hd->httpd_task)
2437  {
2439  hd->httpd_task = NULL;
2440  }
2442  if (hd == httpd)
2443  httpd = NULL;
2444  GNUNET_free(hd);
2445 }
2446 
2447 
2453 static void
2455 {
2456  struct MhdHttpList *hd = cls;
2457 
2458  hd->httpd_task = NULL;
2459  kill_httpd(hd);
2460 }
2461 
2462 
2468 static void
2469 do_httpd(void *cls);
2470 
2471 
2479 static void
2481 {
2482  fd_set rs;
2483  fd_set ws;
2484  fd_set es;
2485  struct GNUNET_NETWORK_FDSet *wrs;
2486  struct GNUNET_NETWORK_FDSet *wws;
2487  int max;
2488  int haveto;
2489  MHD_UNSIGNED_LONG_LONG timeout;
2490  struct GNUNET_TIME_Relative tv;
2491 
2492  FD_ZERO(&rs);
2493  FD_ZERO(&ws);
2494  FD_ZERO(&es);
2495  max = -1;
2496  if (MHD_YES !=
2497  MHD_get_fdset(hd->daemon,
2498  &rs,
2499  &ws,
2500  &es,
2501  &max))
2502  {
2503  kill_httpd(hd);
2504  return;
2505  }
2506  haveto = MHD_get_timeout(hd->daemon,
2507  &timeout);
2508  if (MHD_YES == haveto)
2509  tv.rel_value_us = (uint64_t)timeout * 1000LL;
2510  else
2512  if (-1 != max)
2513  {
2516  GNUNET_NETWORK_fdset_copy_native(wrs, &rs, max + 1);
2517  GNUNET_NETWORK_fdset_copy_native(wws, &ws, max + 1);
2518  }
2519  else
2520  {
2521  wrs = NULL;
2522  wws = NULL;
2523  }
2524  if (NULL != hd->httpd_task)
2525  {
2527  hd->httpd_task = NULL;
2528  }
2529  if ((MHD_YES != haveto) &&
2530  (-1 == max) &&
2531  (hd != httpd))
2532  {
2533  /* daemon is idle, kill after timeout */
2535  &kill_httpd_task,
2536  hd);
2537  }
2538  else
2539  {
2540  hd->httpd_task =
2542  tv, wrs, wws,
2543  &do_httpd, hd);
2544  }
2545  if (NULL != wrs)
2547  if (NULL != wws)
2549 }
2550 
2551 
2557 static void
2558 do_httpd(void *cls)
2559 {
2560  struct MhdHttpList *hd = cls;
2561 
2562  hd->httpd_task = NULL;
2563  MHD_run(hd->daemon);
2564  schedule_httpd(hd);
2565 }
2566 
2567 
2573 static void
2575 {
2576  if (NULL != hd->httpd_task)
2579  hd);
2580 }
2581 
2582 
2590 static void*
2591 load_file(const char* filename,
2592  unsigned int* size)
2593 {
2594  void *buffer;
2595  uint64_t fsize;
2596 
2597  if (GNUNET_OK !=
2598  GNUNET_DISK_file_size(filename,
2599  &fsize,
2600  GNUNET_YES,
2601  GNUNET_YES))
2602  return NULL;
2603  if (fsize > MAX_PEM_SIZE)
2604  return NULL;
2605  *size = (unsigned int)fsize;
2606  buffer = GNUNET_malloc(*size);
2607  if (fsize !=
2608  GNUNET_DISK_fn_read(filename,
2609  buffer,
2610  (size_t)fsize))
2611  {
2612  GNUNET_free(buffer);
2613  return NULL;
2614  }
2615  return buffer;
2616 }
2617 
2618 
2626 static int
2627 load_key_from_file(gnutls_x509_privkey_t key,
2628  const char* keyfile)
2629 {
2630  gnutls_datum_t key_data;
2631  int ret;
2632 
2633  key_data.data = load_file(keyfile,
2634  &key_data.size);
2635  if (NULL == key_data.data)
2636  return GNUNET_SYSERR;
2637  ret = gnutls_x509_privkey_import(key, &key_data,
2638  GNUTLS_X509_FMT_PEM);
2639  if (GNUTLS_E_SUCCESS != ret)
2640  {
2642  _("Unable to import private key from file `%s'\n"),
2643  keyfile);
2644  }
2645  GNUNET_free_non_null(key_data.data);
2646  return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2647 }
2648 
2649 
2657 static int
2658 load_cert_from_file(gnutls_x509_crt_t crt,
2659  const char* certfile)
2660 {
2661  gnutls_datum_t cert_data;
2662  int ret;
2663 
2664  cert_data.data = load_file(certfile,
2665  &cert_data.size);
2666  if (NULL == cert_data.data)
2667  return GNUNET_SYSERR;
2668  ret = gnutls_x509_crt_import(crt,
2669  &cert_data,
2670  GNUTLS_X509_FMT_PEM);
2671  if (GNUTLS_E_SUCCESS != ret)
2672  {
2674  _("Unable to import certificate from `%s'\n"),
2675  certfile);
2676  }
2677  GNUNET_free_non_null(cert_data.data);
2678  return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2679 }
2680 
2681 
2688 static struct ProxyGNSCertificate *
2690 {
2691  unsigned int serial;
2692  size_t key_buf_size;
2693  size_t cert_buf_size;
2694  gnutls_x509_crt_t request;
2695  time_t etime;
2696  struct tm *tm_data;
2697  struct ProxyGNSCertificate *pgc;
2698 
2700  "Generating x.509 certificate for `%s'\n",
2701  name);
2702  GNUNET_break(GNUTLS_E_SUCCESS == gnutls_x509_crt_init(&request));
2703  GNUNET_break(GNUTLS_E_SUCCESS == gnutls_x509_crt_set_key(request, proxy_ca.key));
2704  pgc = GNUNET_new(struct ProxyGNSCertificate);
2705  gnutls_x509_crt_set_dn_by_oid(request,
2706  GNUTLS_OID_X520_COUNTRY_NAME,
2707  0,
2708  "ZZ",
2709  strlen("ZZ"));
2710  gnutls_x509_crt_set_dn_by_oid(request,
2711  GNUTLS_OID_X520_ORGANIZATION_NAME,
2712  0,
2713  "GNU Name System",
2714  strlen("GNU Name System"));
2715  gnutls_x509_crt_set_dn_by_oid(request,
2716  GNUTLS_OID_X520_COMMON_NAME,
2717  0,
2718  name,
2719  strlen(name));
2720  gnutls_x509_crt_set_subject_alternative_name(request,
2721  GNUTLS_SAN_DNSNAME,
2722  name);
2723  GNUNET_break(GNUTLS_E_SUCCESS ==
2724  gnutls_x509_crt_set_version(request,
2725  3));
2726  gnutls_rnd(GNUTLS_RND_NONCE,
2727  &serial,
2728  sizeof(serial));
2729  gnutls_x509_crt_set_serial(request,
2730  &serial,
2731  sizeof(serial));
2732  etime = time(NULL);
2733  tm_data = localtime(&etime);
2734  tm_data->tm_hour--;
2735  etime = mktime(tm_data);
2736  gnutls_x509_crt_set_activation_time(request,
2737  etime);
2738  tm_data->tm_year++;
2739  etime = mktime(tm_data);
2740  gnutls_x509_crt_set_expiration_time(request,
2741  etime);
2742  gnutls_x509_crt_sign2(request,
2743  proxy_ca.cert,
2744  proxy_ca.key,
2745  GNUTLS_DIG_SHA512,
2746  0);
2747  key_buf_size = sizeof(pgc->key);
2748  cert_buf_size = sizeof(pgc->cert);
2749  gnutls_x509_crt_export(request,
2750  GNUTLS_X509_FMT_PEM,
2751  pgc->cert,
2752  &cert_buf_size);
2753  gnutls_x509_privkey_export(proxy_ca.key,
2754  GNUTLS_X509_FMT_PEM,
2755  pgc->key,
2756  &key_buf_size);
2757  gnutls_x509_crt_deinit(request);
2758  return pgc;
2759 }
2760 
2761 
2769 static void
2771  const char *fm,
2772  va_list ap)
2773 {
2774  /* do nothing */
2775 }
2776 
2777 
2784 static struct MhdHttpList *
2786 {
2787  struct MhdHttpList *hd;
2788  struct ProxyGNSCertificate *pgc;
2789 
2790  if (NULL == domain)
2791  {
2792  GNUNET_break(0);
2793  return NULL;
2794  }
2795  for (hd = mhd_httpd_head; NULL != hd; hd = hd->next)
2796  if ((NULL != hd->domain) &&
2797  (0 == strcmp(hd->domain, domain)))
2798  return hd;
2800  "Starting fresh MHD HTTPS instance for domain `%s'\n",
2801  domain);
2802  pgc = generate_gns_certificate(domain);
2803  hd = GNUNET_new(struct MhdHttpList);
2804  hd->is_ssl = GNUNET_YES;
2805  hd->domain = GNUNET_strdup(domain);
2806  hd->proxy_cert = pgc;
2807  hd->daemon = MHD_start_daemon(MHD_USE_DEBUG | MHD_USE_SSL | MHD_USE_NO_LISTEN_SOCKET | MHD_ALLOW_SUSPEND_RESUME,
2808  0,
2809  NULL, NULL,
2810  &create_response, hd,
2811  MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int)16,
2812  MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, NULL,
2813  MHD_OPTION_NOTIFY_CONNECTION, &mhd_connection_cb, NULL,
2814  MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL,
2815  MHD_OPTION_EXTERNAL_LOGGER, &mhd_error_log_callback, NULL,
2816  MHD_OPTION_HTTPS_MEM_KEY, pgc->key,
2817  MHD_OPTION_HTTPS_MEM_CERT, pgc->cert,
2818  MHD_OPTION_END);
2819  if (NULL == hd->daemon)
2820  {
2821  GNUNET_free(pgc);
2822  GNUNET_free(hd);
2823  return NULL;
2824  }
2825  GNUNET_CONTAINER_DLL_insert(mhd_httpd_head,
2826  mhd_httpd_tail,
2827  hd);
2828  return hd;
2829 }
2830 
2831 
2839 static void
2841 {
2842  struct Socks5Request *s5r = cls;
2843 
2844  s5r->timeout_task = NULL;
2845  cleanup_s5r(s5r);
2846 }
2847 
2848 
2857 static void
2859 {
2860  struct MhdHttpList *hd;
2861  int fd;
2862  const struct sockaddr *addr;
2863  socklen_t len;
2864  char *domain;
2865 
2866  if (GNUNET_YES == s5r->is_tls)
2867  {
2868  GNUNET_asprintf(&domain,
2869  "%s",
2870  s5r->domain);
2871  hd = lookup_ssl_httpd(domain);
2872  if (NULL == hd)
2873  {
2875  _("Failed to start HTTPS server for `%s'\n"),
2876  s5r->domain);
2877  cleanup_s5r(s5r);
2878  GNUNET_free(domain);
2879  return;
2880  }
2881  }
2882  else
2883  {
2884  domain = NULL;
2885  GNUNET_assert(NULL != httpd);
2886  hd = httpd;
2887  }
2888  fd = GNUNET_NETWORK_get_fd(s5r->sock);
2889  addr = GNUNET_NETWORK_get_addr(s5r->sock);
2890  len = GNUNET_NETWORK_get_addrlen(s5r->sock);
2892  if (MHD_YES !=
2893  MHD_add_connection(hd->daemon,
2894  fd,
2895  addr,
2896  len))
2897  {
2899  _("Failed to pass client to MHD\n"));
2900  cleanup_s5r(s5r);
2901  GNUNET_free_non_null(domain);
2902  return;
2903  }
2904  s5r->hd = hd;
2905  schedule_httpd(hd);
2908  s5r);
2909  GNUNET_free_non_null(domain);
2910 }
2911 
2912 
2913 /* ********************* SOCKS handling ************************* */
2914 
2915 
2921 static void
2922 do_write(void *cls)
2923 {
2924  struct Socks5Request *s5r = cls;
2925  ssize_t len;
2926 
2927  s5r->wtask = NULL;
2928  len = GNUNET_NETWORK_socket_send(s5r->sock,
2929  s5r->wbuf,
2930  s5r->wbuf_len);
2931  if (len <= 0)
2932  {
2933  /* write error: connection closed, shutdown, etc.; just clean up */
2935  "Write Error\n");
2936  cleanup_s5r(s5r);
2937  return;
2938  }
2939  memmove(s5r->wbuf,
2940  &s5r->wbuf[len],
2941  s5r->wbuf_len - len);
2942  s5r->wbuf_len -= len;
2943  if (s5r->wbuf_len > 0)
2944  {
2945  /* not done writing */
2946  s5r->wtask =
2948  s5r->sock,
2949  &do_write, s5r);
2950  return;
2951  }
2952 
2953  /* we're done writing, continue with state machine! */
2954 
2955  switch (s5r->state)
2956  {
2957  case SOCKS5_INIT:
2958  GNUNET_assert(0);
2959  break;
2960 
2961  case SOCKS5_REQUEST:
2962  GNUNET_assert(NULL != s5r->rtask);
2963  break;
2964 
2965  case SOCKS5_DATA_TRANSFER:
2966  setup_data_transfer(s5r);
2967  return;
2968 
2970  cleanup_s5r(s5r);
2971  return;
2972 
2973  default:
2974  GNUNET_break(0);
2975  break;
2976  }
2977 }
2978 
2979 
2986 static void
2988  enum Socks5StatusCode sc)
2989 {
2990  struct Socks5ServerResponseMessage *s_resp;
2991 
2992  s_resp = (struct Socks5ServerResponseMessage *)&s5r->wbuf[s5r->wbuf_len];
2993  memset(s_resp, 0, sizeof(struct Socks5ServerResponseMessage));
2994  s_resp->version = SOCKS_VERSION_5;
2995  s_resp->reply = sc;
2997  if (NULL != s5r->wtask)
2998  s5r->wtask =
3000  s5r->sock,
3001  &do_write, s5r);
3002 }
3003 
3004 
3010 static void
3012 {
3013  struct Socks5ServerResponseMessage *s_resp;
3014 
3015  s_resp = (struct Socks5ServerResponseMessage *)&s5r->wbuf[s5r->wbuf_len];
3016  s_resp->version = SOCKS_VERSION_5;
3018  s_resp->reserved = 0;
3019  s_resp->addr_type = SOCKS5_AT_IPV4;
3020  /* zero out IPv4 address and port */
3021  memset(&s_resp[1],
3022  0,
3023  sizeof(struct in_addr) + sizeof(uint16_t));
3024  s5r->wbuf_len += sizeof(struct Socks5ServerResponseMessage) +
3025  sizeof(struct in_addr) + sizeof(uint16_t);
3026  if (NULL == s5r->wtask)
3027  s5r->wtask =
3029  s5r->sock,
3030  &do_write, s5r);
3031 }
3032 
3033 
3042 static void
3044  int tld,
3045  uint32_t rd_count,
3046  const struct GNUNET_GNSRECORD_Data *rd)
3047 {
3048  struct Socks5Request *s5r = cls;
3049  const struct GNUNET_GNSRECORD_Data *r;
3050  int got_ip;
3051 
3052  s5r->gns_lookup = NULL;
3053  s5r->is_gns = tld;
3054  got_ip = GNUNET_NO;
3055  for (uint32_t i = 0; i < rd_count; i++)
3056  {
3057  r = &rd[i];
3058  switch (r->record_type)
3059  {
3061  {
3062  struct sockaddr_in *in;
3063 
3064  if (sizeof(struct in_addr) != r->data_size)
3065  {
3066  GNUNET_break_op(0);
3067  break;
3068  }
3069  if (GNUNET_YES == got_ip)
3070  break;
3071  if (GNUNET_OK !=
3072  GNUNET_NETWORK_test_pf(PF_INET))
3073  break;
3074  got_ip = GNUNET_YES;
3075  in = (struct sockaddr_in *)&s5r->destination_address;
3076  in->sin_family = AF_INET;
3077  GNUNET_memcpy(&in->sin_addr,
3078  r->data,
3079  r->data_size);
3080  in->sin_port = htons(s5r->port);
3081 #if HAVE_SOCKADDR_IN_SIN_LEN
3082  in->sin_len = sizeof(*in);
3083 #endif
3084  }
3085  break;
3086 
3088  {
3089  struct sockaddr_in6 *in;
3090 
3091  if (sizeof(struct in6_addr) != r->data_size)
3092  {
3093  GNUNET_break_op(0);
3094  break;
3095  }
3096  if (GNUNET_YES == got_ip)
3097  break;
3098  if (GNUNET_YES == disable_v6)
3099  break;
3100  if (GNUNET_OK !=
3101  GNUNET_NETWORK_test_pf(PF_INET6))
3102  break;
3103  /* FIXME: allow user to disable IPv6 per configuration option... */
3104  got_ip = GNUNET_YES;
3105  in = (struct sockaddr_in6 *)&s5r->destination_address;
3106  in->sin6_family = AF_INET6;
3107  GNUNET_memcpy(&in->sin6_addr,
3108  r->data,
3109  r->data_size);
3110  in->sin6_port = htons(s5r->port);
3111 #if HAVE_SOCKADDR_IN_SIN_LEN
3112  in->sin6_len = sizeof(*in);
3113 #endif
3114  }
3115  break;
3116 
3118  GNUNET_break(0); /* should have been translated within GNS */
3119  break;
3120 
3122  GNUNET_free_non_null(s5r->leho);
3123  s5r->leho = GNUNET_strndup(r->data,
3124  r->data_size);
3125  break;
3126 
3128  {
3129  const struct GNUNET_GNSRECORD_BoxRecord *box;
3130 
3131  if (r->data_size < sizeof(struct GNUNET_GNSRECORD_BoxRecord))
3132  {
3133  GNUNET_break_op(0);
3134  break;
3135  }
3136  box = r->data;
3137  if ((ntohl(box->record_type) != GNUNET_DNSPARSER_TYPE_TLSA) ||
3138  (ntohs(box->protocol) != IPPROTO_TCP) ||
3139  (ntohs(box->service) != s5r->port))
3140  break; /* BOX record does not apply */
3141  if (s5r->num_danes >= MAX_DANES)
3142  {
3143  GNUNET_break(0); /* MAX_DANES too small */
3144  break;
3145  }
3146  s5r->is_tls = GNUNET_YES; /* This should be TLS */
3147  s5r->dane_data_len[s5r->num_danes]
3148  = r->data_size - sizeof(struct GNUNET_GNSRECORD_BoxRecord);
3149  s5r->dane_data[s5r->num_danes]
3150  = GNUNET_memdup(&box[1],
3151  s5r->dane_data_len[s5r->num_danes]);
3152  s5r->num_danes++;
3153  break;
3154  }
3155 
3156  default:
3157  /* don't care */
3158  break;
3159  }
3160  }
3161  if ((GNUNET_YES != got_ip) &&
3162  (GNUNET_YES == tld))
3163  {
3165  "Name resolution failed to yield useful IP address.\n");
3168  return;
3169  }
3170  s5r->state = SOCKS5_DATA_TRANSFER;
3171  signal_socks_success(s5r);
3172 }
3173 
3174 
3181 static void
3183  size_t len)
3184 {
3185  GNUNET_assert(len <= s5r->rbuf_len);
3186  memmove(s5r->rbuf,
3187  &s5r->rbuf[len],
3188  s5r->rbuf_len - len);
3189  s5r->rbuf_len -= len;
3190 }
3191 
3192 
3198 static void
3199 do_s5r_read(void *cls)
3200 {
3201  struct Socks5Request *s5r = cls;
3202  const struct Socks5ClientHelloMessage *c_hello;
3203  struct Socks5ServerHelloMessage *s_hello;
3204  const struct Socks5ClientRequestMessage *c_req;
3205  ssize_t rlen;
3206  size_t alen;
3207  const struct GNUNET_SCHEDULER_TaskContext *tc;
3208 
3209  s5r->rtask = NULL;
3211  if ((NULL != tc->read_ready) &&
3213  s5r->sock)))
3214  {
3215  rlen = GNUNET_NETWORK_socket_recv(s5r->sock,
3216  &s5r->rbuf[s5r->rbuf_len],
3217  sizeof(s5r->rbuf) - s5r->rbuf_len);
3218  if (rlen <= 0)
3219  {
3221  "socks5 client disconnected.\n");
3222  cleanup_s5r(s5r);
3223  return;
3224  }
3225  s5r->rbuf_len += rlen;
3226  }
3228  s5r->sock,
3229  &do_s5r_read, s5r);
3231  "Processing %zu bytes of socks data in state %d\n",
3232  s5r->rbuf_len,
3233  s5r->state);
3234  switch (s5r->state)
3235  {
3236  case SOCKS5_INIT:
3237  c_hello = (const struct Socks5ClientHelloMessage*)&s5r->rbuf;
3238  if ((s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)) ||
3239  (s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage) + c_hello->num_auth_methods))
3240  return; /* need more data */
3241  if (SOCKS_VERSION_5 != c_hello->version)
3242  {
3244  _("Unsupported socks version %d\n"),
3245  (int)c_hello->version);
3246  cleanup_s5r(s5r);
3247  return;
3248  }
3249  clear_from_s5r_rbuf(s5r,
3250  sizeof(struct Socks5ClientHelloMessage) + c_hello->num_auth_methods);
3251  GNUNET_assert(0 == s5r->wbuf_len);
3252  s_hello = (struct Socks5ServerHelloMessage *)&s5r->wbuf;
3253  s5r->wbuf_len = sizeof(struct Socks5ServerHelloMessage);
3254  s_hello->version = SOCKS_VERSION_5;
3255  s_hello->auth_method = SOCKS_AUTH_NONE;
3256  GNUNET_assert(NULL == s5r->wtask);
3258  s5r->sock,
3259  &do_write, s5r);
3260  s5r->state = SOCKS5_REQUEST;
3261  return;
3262 
3263  case SOCKS5_REQUEST:
3264  c_req = (const struct Socks5ClientRequestMessage *)&s5r->rbuf;
3265  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage))
3266  return;
3267  switch (c_req->command)
3268  {
3269  case SOCKS5_CMD_TCP_STREAM:
3270  /* handled below */
3271  break;
3272 
3273  default:
3275  _("Unsupported socks command %d\n"),
3276  (int)c_req->command);
3279  return;
3280  }
3281  switch (c_req->addr_type)
3282  {
3283  case SOCKS5_AT_IPV4:
3284  {
3285  const struct in_addr *v4 = (const struct in_addr *)&c_req[1];
3286  const uint16_t *port = (const uint16_t *)&v4[1];
3287  struct sockaddr_in *in;
3288 
3289  s5r->port = ntohs(*port);
3290  alen = sizeof(struct in_addr);
3291  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage) +
3292  alen + sizeof(uint16_t))
3293  return; /* need more data */
3294  in = (struct sockaddr_in *)&s5r->destination_address;
3295  in->sin_family = AF_INET;
3296  in->sin_addr = *v4;
3297  in->sin_port = *port;
3298 #if HAVE_SOCKADDR_IN_SIN_LEN
3299  in->sin_len = sizeof(*in);
3300 #endif
3301  s5r->state = SOCKS5_DATA_TRANSFER;
3302  }
3303  break;
3304 
3305  case SOCKS5_AT_IPV6:
3306  {
3307  const struct in6_addr *v6 = (const struct in6_addr *)&c_req[1];
3308  const uint16_t *port = (const uint16_t *)&v6[1];
3309  struct sockaddr_in6 *in;
3310 
3311  s5r->port = ntohs(*port);
3312  alen = sizeof(struct in6_addr);
3313  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage) +
3314  alen + sizeof(uint16_t))
3315  return; /* need more data */
3316  in = (struct sockaddr_in6 *)&s5r->destination_address;
3317  in->sin6_family = AF_INET6;
3318  in->sin6_addr = *v6;
3319  in->sin6_port = *port;
3320 #if HAVE_SOCKADDR_IN_SIN_LEN
3321  in->sin6_len = sizeof(*in);
3322 #endif
3323  s5r->state = SOCKS5_DATA_TRANSFER;
3324  }
3325  break;
3326 
3327  case SOCKS5_AT_DOMAINNAME:
3328  {
3329  const uint8_t *dom_len;
3330  const char *dom_name;
3331  const uint16_t *port;
3332 
3333  dom_len = (const uint8_t *)&c_req[1];
3334  alen = *dom_len + 1;
3335  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage) +
3336  alen + sizeof(uint16_t))
3337  return; /* need more data */
3338  dom_name = (const char *)&dom_len[1];
3339  port = (const uint16_t*)&dom_name[*dom_len];
3340  s5r->domain = GNUNET_strndup(dom_name,
3341  *dom_len);
3343  "Requested connection is to %s:%d\n",
3344  //(HTTPS_PORT == s5r->port) ? "s" : "",
3345  s5r->domain,
3346  ntohs(*port));
3347  s5r->state = SOCKS5_RESOLVING;
3348  s5r->port = ntohs(*port);
3349  s5r->is_tls = (HTTPS_PORT == s5r->port) ? GNUNET_YES : GNUNET_NO;
3350  s5r->gns_lookup = GNUNET_GNS_lookup_with_tld(gns_handle,
3351  s5r->domain,
3353  GNUNET_NO /* only cached */,
3355  s5r);
3356  break;
3357  }
3358 
3359  default:
3361  _("Unsupported socks address type %d\n"),
3362  (int)c_req->addr_type);
3365  return;
3366  }
3367  clear_from_s5r_rbuf(s5r,
3368  sizeof(struct Socks5ClientRequestMessage) +
3369  alen + sizeof(uint16_t));
3370  if (0 != s5r->rbuf_len)
3371  {
3372  /* read more bytes than healthy, why did the client send more!? */
3373  GNUNET_break_op(0);
3376  return;
3377  }
3378  if (SOCKS5_DATA_TRANSFER == s5r->state)
3379  {
3380  /* if we are not waiting for GNS resolution, signal success */
3381  signal_socks_success(s5r);
3382  }
3383  /* We are done reading right now */
3385  s5r->rtask = NULL;
3386  return;
3387 
3388  case SOCKS5_RESOLVING:
3389  GNUNET_assert(0);
3390  return;
3391 
3392  case SOCKS5_DATA_TRANSFER:
3393  GNUNET_assert(0);
3394  return;
3395 
3396  default:
3397  GNUNET_assert(0);
3398  return;
3399  }
3400 }
3401 
3402 
3409 static void
3410 do_accept(void *cls)
3411 {
3412  struct GNUNET_NETWORK_Handle *lsock = cls;
3413  struct GNUNET_NETWORK_Handle *s;
3414  struct Socks5Request *s5r;
3415 
3416  GNUNET_assert(NULL != lsock);
3417  if (lsock == lsock4)
3419  lsock,
3420  &do_accept,
3421  lsock);
3422  else if (lsock == lsock6)
3424  lsock,
3425  &do_accept,
3426  lsock);
3427  else
3428  GNUNET_assert(0);
3429  s = GNUNET_NETWORK_socket_accept(lsock,
3430  NULL,
3431  NULL);
3432  if (NULL == s)
3433  {
3435  "accept");
3436  return;
3437  }
3439  "Got an inbound connection, waiting for data\n");
3440  s5r = GNUNET_new(struct Socks5Request);
3441  GNUNET_CONTAINER_DLL_insert(s5r_head,
3442  s5r_tail,
3443  s5r);
3444  s5r->sock = s;
3445  s5r->state = SOCKS5_INIT;
3447  s5r->sock,
3448  &do_s5r_read,
3449  s5r);
3450 }
3451 
3452 
3453 /* ******************* General / main code ********************* */
3454 
3455 
3461 static void
3462 do_shutdown(void *cls)
3463 {
3465  "Shutting down...\n");
3466  /* MHD requires resuming before destroying the daemons */
3467  for (struct Socks5Request *s5r = s5r_head;
3468  NULL != s5r;
3469  s5r = s5r->next)
3470  {
3471  if (s5r->suspended)
3472  {
3473  s5r->suspended = GNUNET_NO;
3474  MHD_resume_connection(s5r->con);
3475  }
3476  }
3477  while (NULL != mhd_httpd_head)
3478  kill_httpd(mhd_httpd_head);
3479  while (NULL != s5r_head)
3480  cleanup_s5r(s5r_head);
3481  if (NULL != lsock4)
3482  {
3484  lsock4 = NULL;
3485  }
3486  if (NULL != lsock6)
3487  {
3489  lsock6 = NULL;
3490  }
3491  if (NULL != curl_multi)
3492  {
3493  curl_multi_cleanup(curl_multi);
3494  curl_multi = NULL;
3495  }
3496  if (NULL != gns_handle)
3497  {
3498  GNUNET_GNS_disconnect(gns_handle);
3499  gns_handle = NULL;
3500  }
3501  if (NULL != curl_download_task)
3502  {
3503  GNUNET_SCHEDULER_cancel(curl_download_task);
3504  curl_download_task = NULL;
3505  }
3506  if (NULL != ltask4)
3507  {
3508  GNUNET_SCHEDULER_cancel(ltask4);
3509  ltask4 = NULL;
3510  }
3511  if (NULL != ltask6)
3512  {
3513  GNUNET_SCHEDULER_cancel(ltask6);
3514  ltask6 = NULL;
3515  }
3516  gnutls_x509_crt_deinit(proxy_ca.cert);
3517  gnutls_x509_privkey_deinit(proxy_ca.key);
3518  gnutls_global_deinit();
3519 }
3520 
3521 
3527 static struct GNUNET_NETWORK_Handle *
3529 {
3530  struct GNUNET_NETWORK_Handle *ls;
3531  struct sockaddr_in sa4;
3532  int eno;
3533 
3534  memset(&sa4, 0, sizeof(sa4));
3535  sa4.sin_family = AF_INET;
3536  sa4.sin_port = htons(port);
3537  sa4.sin_addr.s_addr = address;
3538 #if HAVE_SOCKADDR_IN_SIN_LEN
3539  sa4.sin_len = sizeof(sa4);
3540 #endif
3541  ls = GNUNET_NETWORK_socket_create(AF_INET,
3542  SOCK_STREAM,
3543  0);
3544  if (NULL == ls)
3545  return NULL;
3546  if (GNUNET_OK !=
3548  (const struct sockaddr *)&sa4,
3549  sizeof(sa4)))
3550  {
3551  eno = errno;
3553  errno = eno;
3554  return NULL;
3555  }
3556  return ls;
3557 }
3558 
3559 
3565 static struct GNUNET_NETWORK_Handle *
3567 {
3568  struct GNUNET_NETWORK_Handle *ls;
3569  struct sockaddr_in6 sa6;
3570  int eno;
3571 
3572  memset(&sa6, 0, sizeof(sa6));
3573  sa6.sin6_family = AF_INET6;
3574  sa6.sin6_port = htons(port);
3575  sa6.sin6_addr = address6;
3576 #if HAVE_SOCKADDR_IN_SIN_LEN
3577  sa6.sin6_len = sizeof(sa6);
3578 #endif
3579  ls = GNUNET_NETWORK_socket_create(AF_INET6,
3580  SOCK_STREAM,
3581  0);
3582  if (NULL == ls)
3583  return NULL;
3584  if (GNUNET_OK !=
3586  (const struct sockaddr *)&sa6,
3587  sizeof(sa6)))
3588  {
3589  eno = errno;
3591  errno = eno;
3592  return NULL;
3593  }
3594  return ls;
3595 }
3596 
3597 
3606 static void
3607 run(void *cls,
3608  char *const *args,
3609  const char *cfgfile,
3610  const struct GNUNET_CONFIGURATION_Handle *c)
3611 {
3612  char* cafile_cfg = NULL;
3613  char* cafile;
3614  char* addr_str;
3615  struct MhdHttpList *hd;
3616 
3617  cfg = c;
3618 
3619  /* Get address to bind to */
3620  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, "gns-proxy",
3621  "BIND_TO",
3622  &addr_str))
3623  {
3624  //No address specified
3626  "Don't know what to bind to...\n");
3627  GNUNET_free(addr_str);
3629  return;
3630  }
3631  if (1 != inet_pton(AF_INET, addr_str, &address))
3632  {
3634  "Unable to parse address %s\n",
3635  addr_str);
3636  GNUNET_free(addr_str);
3638  return;
3639  }
3640  GNUNET_free(addr_str);
3641  /* Get address to bind to */
3642  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, "gns-proxy",
3643  "BIND_TO6",
3644  &addr_str))
3645  {
3646  //No address specified
3648  "Don't know what to bind6 to...\n");
3649  GNUNET_free(addr_str);
3651  return;
3652  }
3653  if (1 != inet_pton(AF_INET6, addr_str, &address6))
3654  {
3656  "Unable to parse IPv6 address %s\n",
3657  addr_str);
3658  GNUNET_free(addr_str);
3660  return;
3661  }
3662  GNUNET_free(addr_str);
3663 
3664  if (NULL == (curl_multi = curl_multi_init()))
3665  {
3667  "Failed to create cURL multi handle!\n");
3668  return;
3669  }
3670  cafile = cafile_opt;
3671  if (NULL == cafile)
3672  {
3673  if (GNUNET_OK !=
3675  "gns-proxy",
3676  "PROXY_CACERT",
3677  &cafile_cfg))
3678  {
3680  "gns-proxy",
3681  "PROXY_CACERT");
3682  return;
3683  }
3684  cafile = cafile_cfg;
3685  }
3687  "Using `%s' as CA\n",
3688  cafile);
3689 
3690  gnutls_global_init();
3691  gnutls_x509_crt_init(&proxy_ca.cert);
3692  gnutls_x509_privkey_init(&proxy_ca.key);
3693 
3694  if ((GNUNET_OK !=
3696  cafile)) ||
3697  (GNUNET_OK !=
3699  cafile)))
3700  {
3702  _("Failed to load X.509 key and certificate from `%s'\n"),
3703  cafile);
3704  gnutls_x509_crt_deinit(proxy_ca.cert);
3705  gnutls_x509_privkey_deinit(proxy_ca.key);
3706  gnutls_global_deinit();
3707  GNUNET_free_non_null(cafile_cfg);
3708  return;
3709  }
3710  GNUNET_free_non_null(cafile_cfg);
3711  if (NULL == (gns_handle = GNUNET_GNS_connect(cfg)))
3712  {
3714  "Unable to connect to GNS!\n");
3715  gnutls_x509_crt_deinit(proxy_ca.cert);
3716  gnutls_x509_privkey_deinit(proxy_ca.key);
3717  gnutls_global_deinit();
3718  return;
3719  }
3721  NULL);
3722 
3723  /* Open listen socket for socks proxy */
3724  lsock6 = bind_v6();
3725  if (NULL == lsock6)
3726  {
3728  "bind");
3729  }
3730  else
3731  {
3732  if (GNUNET_OK !=
3734  5))
3735  {
3737  "listen");
3739  lsock6 = NULL;
3740  }
3741  else
3742  {
3744  lsock6,
3745  &do_accept,
3746  lsock6);
3747  }
3748  }
3749  lsock4 = bind_v4();
3750  if (NULL == lsock4)
3751  {
3753  "bind");
3754  }
3755  else
3756  {
3757  if (GNUNET_OK !=
3759  5))
3760  {
3762  "listen");
3764  lsock4 = NULL;
3765  }
3766  else
3767  {
3769  lsock4,
3770  &do_accept,
3771  lsock4);
3772  }
3773  }
3774  if ((NULL == lsock4) &&
3775  (NULL == lsock6))
3776  {
3778  return;
3779  }
3780  if (0 != curl_global_init(CURL_GLOBAL_WIN32))
3781  {
3783  "cURL global init failed!\n");
3785  return;
3786  }
3788  "Proxy listens on port %u\n",
3789  (unsigned int)port);
3790 
3791  /* start MHD daemon for HTTP */
3792  hd = GNUNET_new(struct MhdHttpList);
3793  hd->daemon = MHD_start_daemon(MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET | MHD_ALLOW_SUSPEND_RESUME,
3794  0,
3795  NULL, NULL,
3796  &create_response, hd,
3797  MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int)16,
3798  MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, NULL,
3799  MHD_OPTION_NOTIFY_CONNECTION, &mhd_connection_cb, NULL,
3800  MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL,
3801  MHD_OPTION_END);
3802  if (NULL == hd->daemon)
3803  {
3804  GNUNET_free(hd);
3806  return;
3807  }
3808  httpd = hd;
3809  GNUNET_CONTAINER_DLL_insert(mhd_httpd_head,
3810  mhd_httpd_tail,
3811  hd);
3812 }
3813 
3814 
3822 int
3823 main(int argc,
3824  char *const *argv)
3825 {
3826  struct GNUNET_GETOPT_CommandLineOption options[] = {
3828  "port",
3829  NULL,
3830  gettext_noop("listen on specified port (default: 7777)"),
3831  &port),
3833  "authority",
3834  NULL,
3835  gettext_noop("pem file to use as CA"),
3836  &cafile_opt),
3838  "disable-ivp6",
3839  gettext_noop("disable use of IPv6"),
3840  &disable_v6),
3841 
3843  };
3844  static const char* page =
3845  "<html><head><title>gnunet-gns-proxy</title>"
3846  "</head><body>cURL fail</body></html>";
3847  int ret;
3848 
3849  if (GNUNET_OK !=
3850  GNUNET_STRINGS_get_utf8_args(argc, argv,
3851  &argc, &argv))
3852  return 2;
3853  GNUNET_log_setup("gnunet-gns-proxy",
3854  "WARNING",
3855  NULL);
3857  = MHD_create_response_from_buffer(strlen(page),
3858  (void *)page,
3859  MHD_RESPMEM_PERSISTENT);
3860 
3861  ret =
3862  (GNUNET_OK ==
3863  GNUNET_PROGRAM_run(argc, argv,
3864  "gnunet-gns-proxy",
3865  _("GNUnet GNS proxy"),
3866  options,
3867  &run, NULL)) ? 0 : 1;
3868  MHD_destroy_response(curl_failure_response);
3869  GNUNET_free_non_null((char *)argv);
3870  return ret;
3871 }
3872 
3873 /* end of gnunet-gns-proxy.c */
struct HttpResponseHeader * header_head
Headers from response.
Socket has been passed to MHD, do not close it anymore.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
int GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition: network.c:696
static struct Socks5Request * s5r_tail
DLL of active socks requests.
Connection to the GNS service.
Definition: gns_api.h:35
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:737
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition: network.c:1068
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.
char * domain
the domain name to server (only important for TLS)
struct sockaddr * GNUNET_NETWORK_get_addr(const struct GNUNET_NETWORK_Handle *desc)
Return the sockaddr for this network handle.
Definition: network.c:1081
#define MHD_CACHE_TIMEOUT
After how long do we clean up unused MHD TLS instances?
uint8_t num_auth_methods
How many authentication methods does the client support.
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
uint16_t service
Service of the boxed record (aka port number), in NBO.
static struct GNUNET_VPN_RedirectionRequest * request
Opaque redirection request handle.
Definition: gnunet-vpn.c:41
uint8_t version
Should be SOCKS_VERSION_5.
static struct MhdHttpList * mhd_httpd_tail
DLL for http/https daemons.
Record type used to box up SRV and TLSA records.
uint64_t rel_value_us
The actual value.
static struct GNUNET_SCHEDULER_Task * ltask4
The listen task ID for IPv4.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
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:804
We&#39;re waiting to get the client hello.
static void mhd_error_log_callback(void *cls, const char *fm, va_list ap)
Function called by MHD with errors, suppresses them all.
static void * mhd_log_callback(void *cls, const char *url, struct MHD_Connection *connection)
Function called when MHD first processes an incoming connection.
struct MhdHttpList * next
DLL for httpds.
socklen_t GNUNET_NETWORK_get_addrlen(const struct GNUNET_NETWORK_Handle *desc)
Return sockaddr length for this network handle.
Definition: network.c:1094
char * value
Header value.
int GNUNET_snprintf(char *buf, size_t size, const char *format,...)
Like snprintf, just aborts if the buffer is of insufficient size.
struct HttpResponseHeader * prev
DLL.
library to make it easy to download JSON replies over HTTP
Context information passed to each scheduler task.
uint8_t addr_type
Address type, an enum Socks5AddressType.
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, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1284
void * GNUNET_GNS_lookup_with_tld_cancel(struct GNUNET_GNS_LookupWithTldRequest *ltr)
Cancel pending lookup request.
Definition: gns_tld_api.c:328
struct GNUNET_SCHEDULER_Task * wtask
Client socket write task.
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:775
struct MHD_Connection * con
MHD connection for this request.
int GNUNET_STRINGS_get_utf8_args(int argc, char *const *argv, int *u8argc, char *const **u8argv)
Returns utf-8 encoded arguments.
Definition: strings.c:1439
#define HTTPS_PORT
Port for HTTPS.
static void do_write(void *cls)
Write data from buffer to socks5 client, then continue with state machine.
static size_t curl_check_hdr(void *buffer, size_t size, size_t nmemb, void *cls)
We&#39;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.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
char * dane_data[32+1]
Payload of the DANE records encountered.
static struct MHD_Response * curl_failure_response
Response we return on cURL failures.
char rbuf[(256+32)]
Read buffer.
int curl_paused
Did we pause CURL processing?
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:410
int dane_data_len[32+1]
Number of bytes in dane_data.
int 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:474
struct GNUNET_GNS_LookupWithTldRequest * GNUNET_GNS_lookup_with_tld(struct GNUNET_GNS_Handle *handle, const char *name, uint32_t type, enum GNUNET_GNS_LocalOptions options, GNUNET_GNS_LookupResultProcessor2 proc, void *proc_cls)
Perform an asynchronous lookup operation on the GNS, determining the zone using the TLD of the given ...
Definition: gns_tld_api.c:240
Server hello in Socks5 protocol.
We&#39;re waiting to get the initial request.
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:1537
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
static void kill_httpd_task(void *cls)
Task run whenever HTTP server is idle for too long.
struct GNUNET_NETWORK_Handle * sock
The client socket.
#define MAX_PEM_SIZE
Largest allowed size for a PEM certificate.
#define IO_BUFFERSIZE
Size of the buffer for the data upload / download.
static struct GNUNET_SCHEDULER_Task * ltask6
The listen task ID for IPv6.
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define HTTP_HANDSHAKE_TIMEOUT
After how long do we clean up Socks5 handles that failed to show any activity with their respective M...
#define MAX_DANES
Maximum number of DANE records we support per domain name (and port and protocol).
size_t data_size
Number of bytes in data.
IPv4 address.
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
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 ...
uint8_t version
Should be SOCKS_VERSION_5.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
Definition of a command line option.
Socks5Commands
Commands in Socks5.
static void do_s5r_read(void *cls)
Read data from incoming Socks5 connection.
A structure for CA cert/key.
static in_addr_t address
The address to bind to.
#define GNUNET_GNSRECORD_TYPE_BOX
Record type for a boxed record (see TLSA/SRV handling in GNS).
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:517
static int ret
Final status code.
Definition: gnunet-arm.c:89
We&#39;ve started receiving upload data from MHD.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
uint8_t reply
Status code, an enum Socks5StatusCode
We&#39;ve finished receiving upload data from MHD.
#define SOCKS_AUTH_NONE
Flag to set for &#39;no authentication&#39;.
SocksPhase
The socks phases.
static struct ProxyCA proxy_ca
The CA for X.509 certificate generation.
IPC messages between GNS API and GNS service.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
struct HttpResponseHeader * next
DLL.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
static struct GNUNET_NETWORK_Handle * lsock6
The listen socket of the proxy for IPv6.
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
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:1108
#define GNUNET_GNSRECORD_TYPE_VPN
Record type for VPN resolution.
char * type
Header type.
size_t io_len
Number of bytes already in the IO buffer.
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.
Socks5StatusCode
Status codes in Socks5 response.
size_t rbuf_len
Number of bytes already in read buffer.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
static struct GNUNET_NETWORK_Handle * lsock4
The listen socket of the proxy for IPv4.
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:610
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:420
static char * cafile_opt
The CA file (pem) to use for the proxy CA.
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.
int main(int argc, char *const *argv)
The main function for gnunet-gns-proxy.
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1254
static uint16_t port
The port the proxy is running on (default 7777)
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
int is_ssl
is this an ssl daemon?
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
static void do_shutdown(void *cls)
Task run on shutdown.
A header list.
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:1237
#define GNUNET_DNSPARSER_MAX_NAME_LENGTH
Maximum length of a name in DNS.
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1238
static void signal_socks_failure(struct Socks5Request *s5r, enum Socks5StatusCode sc)
Return a server response message indicating a failure to the client.
struct HttpResponseHeader * header_tail
Headers from response.
char wbuf[(256+32)]
Write buffer.
int ssl_checked
X.509 Certificate status.
Establish TCP/IP stream.
static void setup_data_transfer(struct Socks5Request *s5r)
We&#39;re done with the Socks5 protocol, now we need to pass the connection data through to the final des...
static int verify
Verify mode.
static int check_ssl_certificate(struct Socks5Request *s5r)
Check that the website has presented us with a valid X.509 certificate.
enum State state
current state of profiling
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition: gnunet-arm.c:114
const void * data
Binary value stored in the DNS record.
int suspended
Did we suspend MHD processing?
unsigned int num_danes
Number of entries used in dane_data_len and dane_data.
static struct GNUNET_GNS_Handle * gns_handle
Handle to the GNS service.
void GNUNET_log_config_missing(enum GNUNET_ErrorType kind, const char *section, const char *option)
Log error message about missing configuration option.
static struct MhdHttpList * httpd
Daemon for HTTP (we have one per X.509 certificate, and then one for all HTTP connections; this is th...
static char * value
Value of the record to add/remove.
Client hello in Socks5 protocol.
struct GNUNET_GNS_LookupWithTldRequest * gns_lookup
Handle to GNS lookup, during SOCKS5_RESOLVING phase.
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
struct curl_slist * headers
HTTP request headers for the curl request.
static void do_accept(void *cls)
Accept new incoming connections.
enum SocksPhase state
The socks state.
struct MhdHttpList * hd
MHD HTTP instance handling this request, NULL for none.
static struct GNUNET_NETWORK_Handle * bind_v6()
Create an IPv6 listen socket bound to our port.
uint8_t reserved
Always zero.
static void * load_file(const char *filename, unsigned int *size)
Read file in filename.
uint8_t auth_method
Chosen authentication method, for us always SOCKS_AUTH_NONE, which skips the authentication step...
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:1264
void GNUNET_GNS_disconnect(struct GNUNET_GNS_Handle *handle)
Shutdown connection with the GNS service.
Definition: gns_api.c:282
#define SOCKS_BUFFERSIZE
Size of the read/write buffers for Socks.
#define GNUNET_MIN(a, b)
Definition: gnunet_common.h:80
#define GNUNET_GNS_PROXY_PORT
Default Socks5 listen port.
char * domain
the domain name to server (only important for TLS)
collection of IO descriptors
struct MHD_Response * response
MHD response object for this request.
static char buf[2048]
static char * filename
static void schedule_httpd(struct MhdHttpList *hd)
Schedule MHD.
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:1784
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
uint8_t resvd
Reserved, always zero.
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:440
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct GNUNET_SCHEDULER_Task * rtask
Client socket read task.
uint16_t protocol
Protocol of the boxed record (6 = TCP, 17 = UDP, etc.).
struct GNUNET_GNS_Handle * GNUNET_GNS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Initialize the connection with the GNS service.
Definition: gns_api.c:260
static int load_cert_from_file(gnutls_x509_crt_t crt, const char *certfile)
Load cert from file.
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
struct Socks5Request * next
DLL.
static struct Socks5Request * s5r_head
DLL of active socks requests.
struct MHD_Daemon * daemon
The daemon handle.
int 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.
static struct MhdHttpList * lookup_ssl_httpd(const char *domain)
Lookup (or create) an TLS MHD instance for a particular domain.
static struct in6_addr address6
The IPv6 address to bind to.
uint16_t port
Desired destination port.
struct GNUNET_SCHEDULER_Task * timeout_task
Timeout task.
Establish TCP port binding.
static uint64_t etime
Expiration string converted to numeric value.
struct GNUNET_HashCode key
The key used in the DHT.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
Finish writing the write buffer, then clean up.
static void cleanup_s5r(struct Socks5Request *s5r)
Clean up s5r handles.
static unsigned int size
Size of the "table".
Definition: peer.c:66
static struct GNUNET_SCHEDULER_Task * curl_download_task
The cURL download task (curl multi API).
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
static ssize_t mhd_content_cb(void *cls, uint64_t pos, char *buf, size_t max)
Callback for MHD response generation.
struct sockaddr_storage destination_address
Once known, what&#39;s the target address for the connection?
uint8_t version
Should be SOCKS_VERSION_5.
const char * name
uint8_t version
Should be SOCKS_VERSION_5.
struct curl_slist * hosts
DNS->IP mappings resolved through GNS.
static struct GNUNET_FS_SearchContext * sc
Definition: gnunet-search.c:37
char key[(10 *1024)]
The private key as PEM.
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
Main function that will be run.
char cert[(10 *1024)]
The certificate as PEM.
Client socks request in Socks5 protocol.
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.
uint32_t record_type
GNS record type of the boxed record.
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition: gnunet-nat.c:85
Server response to client requests in Socks5 protocol.
int 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:254
#define GNUNET_DNSPARSER_TYPE_TLSA
static size_t curl_download_cb(void *ptr, size_t size, size_t nmemb, void *ctx)
Handle response payload data from cURL.
A structure for all running Httpds.
static void kill_httpd(struct MhdHttpList *hd)
Kill the given MHD daemon.
We&#39;ve finished uploading data via CURL and can now download.
gnutls_x509_privkey_t key
The private key.
IPv6 address.
#define GNUNET_GNSRECORD_TYPE_LEHO
Record type for GNS legacy hostnames ("LEHO").
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
static struct MhdHttpList * mhd_httpd_head
DLL for http/https daemons.
struct Socks5Request * prev
DLL.
int is_gns
Was the hostname resolved via GNS?
uint32_t record_type
Type of the GNS/DNS record.
char * leho
DNS Legacy Host Name as given by GNS, NULL if not given.
#define GNUNET_DNSPARSER_TYPE_AAAA
configuration data
Definition: configuration.c:83
static void curl_download_prepare()
Ask cURL for the select() sets and schedule cURL operations.
static struct GNUNET_NETWORK_Handle * bind_v4()
Create an IPv4 listen socket bound to our port.
We&#39;ve finished receiving download data from cURL.
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 ProxyGNSCertificate * proxy_cert
Optional proxy certificate used.
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:131
static void do_httpd(void *cls)
Task run whenever HTTP server operations are pending.
int 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.
char io_buf[CURL_MAX_WRITE_SIZE]
Buffer we use for moving data between MHD and curl (in both directions).
handle to a socket
Definition: network.c:46
int is_tls
This is (probably) a TLS connection.
int GNUNET_PROGRAM_run(int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls)
Run a standard GNUnet command startup sequence (initialize loggers and configuration, parse options).
Definition: program.c:367
static void curl_task_download(void *cls)
Task that is run when we are ready to receive more data from curl.
static int load_key_from_file(gnutls_x509_privkey_t key, const char *keyfile)
Load PEM key from file.
static void signal_socks_success(struct Socks5Request *s5r)
Return a server response message indicating success.
static void timeout_s5r_handshake(void *cls)
Task run when a Socks5Request somehow fails to be associated with an MHD connection (i...
#define GNUNET_YES
Definition: gnunet_common.h:77
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:1467
static void clear_from_s5r_rbuf(struct Socks5Request *s5r, size_t len)
Remove the first len bytes from the beginning of the read buffer.
Socks5AddressType
Address types in Socks5.
static struct ProxyGNSCertificate * generate_gns_certificate(const char *name)
Generate new certificate for specific name.
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.
We are currently resolving the destination.
Establish UDP port binding.
static int 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.
gnutls_x509_crt_t cert
The certificate.
char * url
The URL to fetch.
Run with the default priority (normal P2P operations).
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
We&#39;re in transfer mode.
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:1017
A structure for socks requests.
Handle to a lookup request.
Definition: gns_tld_api.c:44
struct MhdHttpList * prev
DLL for httpds.
static CURLM * curl_multi
The cURL multi handle.
#define SOCKS_VERSION_5
Which SOCKS version do we speak?
#define GNUNET_DNSPARSER_TYPE_A
uint8_t command
Command code, we only uspport SOCKS5_CMD_TCP_STREAM.
static void run_mhd_now(struct MhdHttpList *hd)
Run MHD now, we have extra data ready for the callback.
int GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:548
unsigned int response_code
HTTP response code to give to MHD for the response.
static size_t curl_upload_cb(void *buf, size_t size, size_t nmemb, void *cls)
cURL callback for uploaded (PUT/POST) data.
Structure for GNS certificates.
#define GNUNET_malloc(size)
Wrapper around malloc.
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:791
int GNUNET_NETWORK_test_pf(int pf)
Test if the given protocol family is supported by this system.
Definition: network.c:78
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_SCHEDULER_Task * httpd_task
The task ID.
static int disable_v6
Disable IPv6.
CURL * curl
Handle to cURL.
Time for relative time used by GNUnet, in microseconds.
size_t wbuf_len
Number of bytes already in write buffer.
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.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
#define gettext_noop(String)
Definition: gettext.h:69
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:900
uint8_t addr_type
Address type, an enum Socks5AddressType.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:956