GNUnet  0.11.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 
51 #define GNUNET_GNS_PROXY_PORT 7777
52 
57 #define MAX_HTTP_URI_LENGTH 2048
58 
63 #define MAX_DANES 32
64 
69 #define IO_BUFFERSIZE CURL_MAX_WRITE_SIZE
70 
76 #define SOCKS_BUFFERSIZE (256 + 32)
77 
81 #define HTTP_PORT 80
82 
86 #define HTTPS_PORT 443
87 
91 #define MAX_PEM_SIZE (10 * 1024)
92 
96 #define MHD_CACHE_TIMEOUT GNUNET_TIME_relative_multiply ( \
97  GNUNET_TIME_UNIT_MINUTES, 5)
98 
103 #define HTTP_HANDSHAKE_TIMEOUT GNUNET_TIME_relative_multiply ( \
104  GNUNET_TIME_UNIT_SECONDS, 15)
105 
106 
114 #define LOG_CURL_EASY(level, fun, rc) \
115  GNUNET_log (level, \
116  _ ("%s failed at %s:%d: `%s'\n"), \
117  fun, \
118  __FILE__, \
119  __LINE__, \
120  curl_easy_strerror (rc))
121 
122 
123 /* *************** Socks protocol definitions (move to TUN?) ****************** */
124 
128 #define SOCKS_VERSION_5 0x05
129 
133 #define SOCKS_AUTH_NONE 0
134 
135 
140 {
145 
150 
155 };
156 
157 
162 {
167 
172 
177 };
178 
179 
184 {
194 };
195 
196 
201 {
205  uint8_t version;
206 
211 
212  /* followed by supported authentication methods, 1 byte per method */
213 };
214 
215 
220 {
224  uint8_t version;
225 
230  uint8_t auth_method;
231 };
232 
233 
238 {
242  uint8_t version;
243 
247  uint8_t command;
248 
252  uint8_t resvd;
253 
257  uint8_t addr_type;
258 
259  /*
260  * Followed by either an ip4/ipv6 address or a domain name with a
261  * length field (uint8_t) in front (depending on @e addr_type).
262  * followed by port number in network byte order (uint16_t).
263  */
264 };
265 
266 
271 {
275  uint8_t version;
276 
280  uint8_t reply;
281 
285  uint8_t reserved;
286 
290  uint8_t addr_type;
291 
292  /*
293  * Followed by either an ip4/ipv6 address or a domain name with a
294  * length field (uint8_t) in front (depending on @e addr_type).
295  * followed by port number in network byte order (uint16_t).
296  */
297 };
298 
299 
300 /* *********************** Datastructures for HTTP handling ****************** */
301 
305 struct ProxyCA
306 {
310  gnutls_x509_crt_t cert;
311 
315  gnutls_x509_privkey_t key;
316 };
317 
318 
323 {
327  char cert[MAX_PEM_SIZE];
328 
333 };
334 
335 
340 {
344  struct MhdHttpList *prev;
345 
349  struct MhdHttpList *next;
350 
354  char *domain;
355 
359  struct MHD_Daemon *daemon;
360 
365 
370 
374  int is_ssl;
375 };
376 
377 
378 /* ***************** Datastructures for Socks handling **************** */
379 
380 
385 {
390 
395 
400 
405 
410 
415 
420 
425 
430 
435 };
436 
437 
442 {
447 
452 
456  char *type;
457 
461  char *value;
462 };
463 
468 {
473 
478 
483 
488 
493 
498 
503 
507  char rbuf[SOCKS_BUFFERSIZE];
508 
512  char wbuf[SOCKS_BUFFERSIZE];
513 
517  char io_buf[IO_BUFFERSIZE];
518 
522  struct MhdHttpList *hd;
523 
527  struct MHD_Connection *con;
528 
532  struct MHD_Response *response;
533 
537  char *domain;
538 
542  char *leho;
543 
547  char *dane_data[MAX_DANES + 1];
548 
552  char *url;
553 
557  CURL *curl;
558 
562  struct curl_slist *headers;
563 
567  struct curl_slist *hosts;
568 
572  unsigned int response_code;
573 
577  int dane_data_len[MAX_DANES + 1];
578 
583  unsigned int num_danes;
584 
588  size_t rbuf_len;
589 
593  size_t wbuf_len;
594 
598  size_t io_len;
599 
603  struct sockaddr_storage destination_address;
604 
609 
613  uint16_t port;
614 
619 
624 
629 
633  int is_gns;
634 
638  int is_tls;
639 
644 
649 };
650 
651 
652 /* *********************** Globals **************************** */
653 
657 static in_addr_t address;
658 
662 static struct in6_addr address6;
663 
667 static uint16_t port = GNUNET_GNS_PROXY_PORT;
668 
672 static char *cafile_opt;
673 
678 
683 
688 
693 
698 
702 static CURLM *curl_multi;
703 
708 
712 static int disable_v6;
713 
718 
723 
728 static struct MhdHttpList *httpd;
729 
733 static struct Socks5Request *s5r_head;
734 
738 static struct Socks5Request *s5r_tail;
739 
743 static struct ProxyCA proxy_ca;
744 
748 static struct MHD_Response *curl_failure_response;
749 
753 static const struct GNUNET_CONFIGURATION_Handle *cfg;
754 
755 
756 /* ************************* Global helpers ********************* */
757 
758 
764 static void
765 run_mhd_now (struct MhdHttpList *hd);
766 
767 
773 static void
775 {
777  "Cleaning up socks request\n");
778  if (NULL != s5r->curl)
779  {
781  "Cleaning up cURL handle\n");
782  curl_multi_remove_handle (curl_multi,
783  s5r->curl);
784  curl_easy_cleanup (s5r->curl);
785  s5r->curl = NULL;
786  }
787  if (s5r->suspended)
788  {
789  s5r->suspended = GNUNET_NO;
790  MHD_resume_connection (s5r->con);
791  }
792  curl_slist_free_all (s5r->headers);
793  if (NULL != s5r->hosts)
794  {
795  curl_slist_free_all (s5r->hosts);
796  }
797  if ((NULL != s5r->response) &&
799  {
800  MHD_destroy_response (s5r->response);
801  s5r->response = NULL;
802  }
803  if (NULL != s5r->rtask)
804  {
806  s5r->rtask = NULL;
807  }
808  if (NULL != s5r->timeout_task)
809  {
811  s5r->timeout_task = NULL;
812  }
813  if (NULL != s5r->wtask)
814  {
816  s5r->wtask = NULL;
817  }
818  if (NULL != s5r->gns_lookup)
819  {
821  s5r->gns_lookup = NULL;
822  }
823  if (NULL != s5r->sock)
824  {
825  if (SOCKS5_SOCKET_WITH_MHD <= s5r->state)
827  else
829  s5r->sock = NULL;
830  }
831  GNUNET_CONTAINER_DLL_remove (s5r_head,
832  s5r_tail,
833  s5r);
835  GNUNET_free_non_null (s5r->leho);
836  GNUNET_free_non_null (s5r->url);
837  for (unsigned int i = 0; i < s5r->num_danes; i++)
838  GNUNET_free (s5r->dane_data[i]);
839  GNUNET_free (s5r);
840 }
841 
842 
843 /* ************************* HTTP handling with cURL *********************** */
844 
845 static void
847 
848 
860 static ssize_t
861 mhd_content_cb (void *cls,
862  uint64_t pos,
863  char*buf,
864  size_t max)
865 {
866  struct Socks5Request *s5r = cls;
867  size_t bytes_to_copy;
868 
869  if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
871  {
872  /* we're still not done with the upload, do not yet
873  start the download, the IO buffer is still full
874  with upload data. */
876  "Pausing MHD download %s%s, not yet ready for download\n",
877  s5r->domain,
878  s5r->url);
879  return 0; /* not yet ready for data download */
880  }
881  bytes_to_copy = GNUNET_MIN (max,
882  s5r->io_len);
883  if ((0 == bytes_to_copy) &&
885  {
887  "Pausing MHD download %s%s, no data available\n",
888  s5r->domain,
889  s5r->url);
890  if (NULL != s5r->curl)
891  {
893  "Continuing CURL interaction for %s%s\n",
894  s5r->domain,
895  s5r->url);
896  if (GNUNET_YES == s5r->curl_paused)
897  {
898  s5r->curl_paused = GNUNET_NO;
899  curl_easy_pause (s5r->curl,
900  CURLPAUSE_CONT);
901  }
903  }
904  if (GNUNET_NO == s5r->suspended)
905  {
906  MHD_suspend_connection (s5r->con);
907  s5r->suspended = GNUNET_YES;
908  }
909  return 0; /* more data later */
910  }
911  if ((0 == bytes_to_copy) &&
913  {
915  "Completed MHD download %s%s\n",
916  s5r->domain,
917  s5r->url);
918  return MHD_CONTENT_READER_END_OF_STREAM;
919  }
921  "Writing %llu/%llu bytes to %s%s\n",
922  (unsigned long long) bytes_to_copy,
923  (unsigned long long) s5r->io_len,
924  s5r->domain,
925  s5r->url);
926  GNUNET_memcpy (buf,
927  s5r->io_buf,
928  bytes_to_copy);
929  memmove (s5r->io_buf,
930  &s5r->io_buf[bytes_to_copy],
931  s5r->io_len - bytes_to_copy);
932  s5r->io_len -= bytes_to_copy;
933  if ((NULL != s5r->curl) &&
934  (GNUNET_YES == s5r->curl_paused))
935  {
937  "Continuing CURL interaction for %s%s\n",
938  s5r->domain,
939  s5r->url);
940  s5r->curl_paused = GNUNET_NO;
941  curl_easy_pause (s5r->curl,
942  CURLPAUSE_CONT);
943  }
944  return bytes_to_copy;
945 }
946 
947 
956 static int
958 {
959  unsigned int cert_list_size;
960  const gnutls_datum_t *chainp;
961  const struct curl_tlssessioninfo *tlsinfo;
962  char certdn[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 3];
963  size_t size;
964  gnutls_x509_crt_t x509_cert;
965  int rc;
966  const char *name;
967 
968  s5r->ssl_checked = GNUNET_YES;
970  "Checking X.509 certificate\n");
971  if (CURLE_OK !=
972  curl_easy_getinfo (s5r->curl,
973  CURLINFO_TLS_SESSION,
974  &tlsinfo))
975  return GNUNET_SYSERR;
976  if (CURLSSLBACKEND_GNUTLS != tlsinfo->backend)
977  {
979  _ ("Unsupported CURL TLS backend %d\n"),
980  tlsinfo->backend);
981  return GNUNET_SYSERR;
982  }
983  chainp = gnutls_certificate_get_peers (tlsinfo->internals,
984  &cert_list_size);
985  if ((! chainp) ||
986  (0 == cert_list_size))
987  return GNUNET_SYSERR;
988 
989  size = sizeof(certdn);
990  /* initialize an X.509 certificate structure. */
991  gnutls_x509_crt_init (&x509_cert);
992  gnutls_x509_crt_import (x509_cert,
993  chainp,
994  GNUTLS_X509_FMT_DER);
995 
996  if (0 != (rc = gnutls_x509_crt_get_dn_by_oid (x509_cert,
997  GNUTLS_OID_X520_COMMON_NAME,
998  0, /* the first and only one */
999  0 /* no DER encoding */,
1000  certdn,
1001  &size)))
1002  {
1004  _ ("Failed to fetch CN from cert: %s\n"),
1005  gnutls_strerror (rc));
1006  gnutls_x509_crt_deinit (x509_cert);
1007  return GNUNET_SYSERR;
1008  }
1009  /* check for TLSA/DANE records */
1010 #if HAVE_GNUTLS_DANE
1011  if (0 != s5r->num_danes)
1012  {
1013  dane_state_t dane_state;
1014  dane_query_t dane_query;
1015  unsigned int verify;
1016 
1017  /* FIXME: add flags to gnutls to NOT read UNBOUND_ROOT_KEY_FILE here! */
1018  if (0 != (rc = dane_state_init (&dane_state,
1019 #ifdef DANE_F_IGNORE_DNSSEC
1020  DANE_F_IGNORE_DNSSEC |
1021 #endif
1022  DANE_F_IGNORE_LOCAL_RESOLVER)))
1023  {
1025  _ ("Failed to initialize DANE: %s\n"),
1026  dane_strerror (rc));
1027  gnutls_x509_crt_deinit (x509_cert);
1028  return GNUNET_SYSERR;
1029  }
1030  s5r->dane_data[s5r->num_danes] = NULL;
1031  s5r->dane_data_len[s5r->num_danes] = 0;
1032  if (0 != (rc = dane_raw_tlsa (dane_state,
1033  &dane_query,
1034  s5r->dane_data,
1035  s5r->dane_data_len,
1036  GNUNET_YES,
1037  GNUNET_NO)))
1038  {
1040  _ ("Failed to parse DANE record: %s\n"),
1041  dane_strerror (rc));
1042  dane_state_deinit (dane_state);
1043  gnutls_x509_crt_deinit (x509_cert);
1044  return GNUNET_SYSERR;
1045  }
1046  if (0 != (rc = dane_verify_crt_raw (dane_state,
1047  chainp,
1048  cert_list_size,
1049  gnutls_certificate_type_get (
1050  tlsinfo->internals),
1051  dane_query,
1052  0, 0,
1053  &verify)))
1054  {
1056  _ ("Failed to verify TLS connection using DANE: %s\n"),
1057  dane_strerror (rc));
1058  dane_query_deinit (dane_query);
1059  dane_state_deinit (dane_state);
1060  gnutls_x509_crt_deinit (x509_cert);
1061  return GNUNET_SYSERR;
1062  }
1063  if (0 != verify)
1064  {
1066  _ (
1067  "Failed DANE verification failed with GnuTLS verify status code: %u\n"),
1068  verify);
1069  dane_query_deinit (dane_query);
1070  dane_state_deinit (dane_state);
1071  gnutls_x509_crt_deinit (x509_cert);
1072  return GNUNET_SYSERR;
1073  }
1074  dane_query_deinit (dane_query);
1075  dane_state_deinit (dane_state);
1076  /* success! */
1077  }
1078  else
1079 #endif
1080  {
1081  /* try LEHO or ordinary domain name X509 verification */
1082  name = s5r->domain;
1083  if (NULL != s5r->leho)
1084  name = s5r->leho;
1085  if (NULL != name)
1086  {
1087  if (0 == (rc = gnutls_x509_crt_check_hostname (x509_cert,
1088  name)))
1089  {
1091  _ (
1092  "TLS certificate subject name (%s) does not match `%s': %d\n"),
1093  certdn,
1094  name,
1095  rc);
1096  gnutls_x509_crt_deinit (x509_cert);
1097  return GNUNET_SYSERR;
1098  }
1099  }
1100  else
1101  {
1102  /* we did not even have the domain name!? */
1103  GNUNET_break (0);
1104  return GNUNET_SYSERR;
1105  }
1106  }
1107  gnutls_x509_crt_deinit (x509_cert);
1108  return GNUNET_OK;
1109 }
1110 
1111 
1124 static size_t
1125 curl_check_hdr (void *buffer,
1126  size_t size,
1127  size_t nmemb,
1128  void *cls)
1129 {
1130  struct Socks5Request *s5r = cls;
1131  struct HttpResponseHeader *header;
1132  size_t bytes = size * nmemb;
1133  char *ndup;
1134  const char *hdr_type;
1135  const char *cookie_domain;
1136  char *hdr_val;
1137  char *new_cookie_hdr;
1138  char *new_location;
1139  size_t offset;
1140  size_t delta_cdomain;
1141  int domain_matched;
1142  char *tok;
1143 
1145  "Receiving HTTP response header from CURL\n");
1146  /* first, check TLS certificate */
1147  if ((GNUNET_YES != s5r->ssl_checked) &&
1148  (GNUNET_YES == s5r->is_tls))
1149  // (HTTPS_PORT == s5r->port))
1150  {
1151  if (GNUNET_OK != check_ssl_certificate (s5r))
1152  return 0;
1153  }
1154  ndup = GNUNET_strndup (buffer,
1155  bytes);
1156  hdr_type = strtok (ndup,
1157  ":");
1158  if (NULL == hdr_type)
1159  {
1160  GNUNET_free (ndup);
1161  return bytes;
1162  }
1163  hdr_val = strtok (NULL,
1164  "");
1165  if (NULL == hdr_val)
1166  {
1167  GNUNET_free (ndup);
1168  return bytes;
1169  }
1170  if (' ' == *hdr_val)
1171  hdr_val++;
1172 
1173  /* custom logic for certain header types */
1174  new_cookie_hdr = NULL;
1175  if ((NULL != s5r->leho) &&
1176  (0 == strcasecmp (hdr_type,
1177  MHD_HTTP_HEADER_SET_COOKIE)))
1178 
1179  {
1180  new_cookie_hdr = GNUNET_malloc (strlen (hdr_val)
1181  + strlen (s5r->domain) + 1);
1182  offset = 0;
1183  domain_matched = GNUNET_NO; /* make sure we match domain at most once */
1184  for (tok = strtok (hdr_val, ";"); NULL != tok; tok = strtok (NULL, ";"))
1185  {
1186  if ((0 == strncasecmp (tok,
1187  " domain",
1188  strlen (" domain"))) &&
1189  (GNUNET_NO == domain_matched))
1190  {
1191  domain_matched = GNUNET_YES;
1192  cookie_domain = tok + strlen (" domain") + 1;
1193  if (strlen (cookie_domain) < strlen (s5r->leho))
1194  {
1195  delta_cdomain = strlen (s5r->leho) - strlen (cookie_domain);
1196  if (0 == strcasecmp (cookie_domain,
1197  s5r->leho + delta_cdomain))
1198  {
1199  offset += sprintf (new_cookie_hdr + offset,
1200  " domain=%s;",
1201  s5r->domain);
1202  continue;
1203  }
1204  }
1205  else if (0 == strcmp (cookie_domain,
1206  s5r->leho))
1207  {
1208  offset += sprintf (new_cookie_hdr + offset,
1209  " domain=%s;",
1210  s5r->domain);
1211  continue;
1212  }
1213  else if (('.' == cookie_domain[0]) &&
1214  (0 == strcmp (&cookie_domain[1],
1215  s5r->leho)))
1216  {
1217  offset += sprintf (new_cookie_hdr + offset,
1218  " domain=.%s;",
1219  s5r->domain);
1220  continue;
1221  }
1223  _ ("Cookie domain `%s' supplied by server is invalid\n"),
1224  tok);
1225  }
1226  GNUNET_memcpy (new_cookie_hdr + offset,
1227  tok,
1228  strlen (tok));
1229  offset += strlen (tok);
1230  new_cookie_hdr[offset++] = ';';
1231  }
1232  hdr_val = new_cookie_hdr;
1233  }
1234 
1235  new_location = NULL;
1236  if (0 == strcasecmp (MHD_HTTP_HEADER_TRANSFER_ENCODING,
1237  hdr_type))
1238  {
1239  /* Ignore transfer encoding, set automatically by MHD if required */
1240  goto cleanup;
1241  }
1242  if ((0 == strcasecmp (MHD_HTTP_HEADER_LOCATION,
1243  hdr_type)))
1244  {
1245  char *leho_host;
1246 
1247  GNUNET_asprintf (&leho_host,
1248  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1249  ? "http://%s"
1250  : "https://%s",
1251  s5r->leho);
1252  if (0 == strncmp (leho_host,
1253  hdr_val,
1254  strlen (leho_host)))
1255  {
1256  GNUNET_asprintf (&new_location,
1257  "%s%s%s",
1258  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1259  ? "http://"
1260  : "https://",
1261  s5r->domain,
1262  hdr_val + strlen (leho_host));
1263  hdr_val = new_location;
1264  }
1265  GNUNET_free (leho_host);
1266  }
1267  if (0 == strcasecmp (MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
1268  hdr_type))
1269  {
1270  char *leho_host;
1271 
1272  GNUNET_asprintf (&leho_host,
1273  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1274  ? "http://%s"
1275  : "https://%s",
1276  s5r->leho);
1277  if (0 == strncmp (leho_host,
1278  hdr_val,
1279  strlen (leho_host)))
1280  {
1281  GNUNET_asprintf (&new_location,
1282  "%s%s",
1283  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1284  ? "http://"
1285  : "https://",
1286  s5r->domain);
1287  hdr_val = new_location;
1288  }
1289  GNUNET_free (leho_host);
1290  }
1291 
1292  /* MHD does not allow certain characters in values, remove those */
1293  if (NULL != (tok = strchr (hdr_val, '\n')))
1294  *tok = '\0';
1295  if (NULL != (tok = strchr (hdr_val, '\r')))
1296  *tok = '\0';
1297  if (NULL != (tok = strchr (hdr_val, '\t')))
1298  *tok = '\0';
1299  if (0 != strlen (hdr_val)) /* Rely in MHD to set those */
1300  {
1302  "Adding header %s: %s to MHD response\n",
1303  hdr_type,
1304  hdr_val);
1305  header = GNUNET_new (struct HttpResponseHeader);
1306  header->type = GNUNET_strdup (hdr_type);
1307  header->value = GNUNET_strdup (hdr_val);
1309  s5r->header_tail,
1310  header);
1311  }
1312 cleanup:
1313  GNUNET_free (ndup);
1314  GNUNET_free_non_null (new_cookie_hdr);
1315  GNUNET_free_non_null (new_location);
1316  return bytes;
1317 }
1318 
1319 
1328 static int
1330 {
1331  long resp_code;
1332  double content_length;
1333 
1334  if (NULL != s5r->response)
1335  {
1337  "Response already set!\n");
1338  return GNUNET_SYSERR;
1339  }
1340 
1341  GNUNET_break (CURLE_OK ==
1342  curl_easy_getinfo (s5r->curl,
1343  CURLINFO_RESPONSE_CODE,
1344  &resp_code));
1345  GNUNET_break (CURLE_OK ==
1346  curl_easy_getinfo (s5r->curl,
1347  CURLINFO_CONTENT_LENGTH_DOWNLOAD,
1348  &content_length));
1350  "Creating MHD response with code %d and size %d for %s%s\n",
1351  (int) resp_code,
1352  (int) content_length,
1353  s5r->domain,
1354  s5r->url);
1355  s5r->response_code = resp_code;
1356  s5r->response = MHD_create_response_from_callback ((-1 == content_length)
1357  ? MHD_SIZE_UNKNOWN
1358  : content_length,
1359  IO_BUFFERSIZE,
1360  &mhd_content_cb,
1361  s5r,
1362  NULL);
1363  for (struct HttpResponseHeader *header = s5r->header_head;
1364  NULL != header;
1365  header = header->next)
1366  {
1367  if (0 == strcasecmp (header->type,
1368  MHD_HTTP_HEADER_CONTENT_LENGTH))
1369  continue; /* MHD won't let us mess with those, for good reason */
1370  if ((0 == strcasecmp (header->type,
1371  MHD_HTTP_HEADER_TRANSFER_ENCODING)) &&
1372  ((0 == strcasecmp (header->value,
1373  "identity")) ||
1374  (0 == strcasecmp (header->value,
1375  "chunked"))))
1376  continue; /* MHD won't let us mess with those, for good reason */
1377  if (MHD_YES !=
1378  MHD_add_response_header (s5r->response,
1379  header->type,
1380  header->value))
1381  {
1382  GNUNET_break (0);
1384  "Failed to add header `%s:%s'\n",
1385  header->type,
1386  header->value);
1387  }
1388  }
1389  /* force connection to be closed after each request, as we
1390  do not support HTTP pipelining (yet, FIXME!) */
1391  /*GNUNET_break (MHD_YES ==
1392  MHD_add_response_header (s5r->response,
1393  MHD_HTTP_HEADER_CONNECTION,
1394  "close"));*/
1395  MHD_resume_connection (s5r->con);
1396  s5r->suspended = GNUNET_NO;
1397  return GNUNET_OK;
1398 }
1399 
1400 
1411 static size_t
1412 curl_download_cb (void *ptr,
1413  size_t size,
1414  size_t nmemb,
1415  void*ctx)
1416 {
1417  struct Socks5Request *s5r = ctx;
1418  size_t total = size * nmemb;
1419 
1421  "Receiving %ux%u bytes for `%s%s' from cURL to download\n",
1422  (unsigned int) size,
1423  (unsigned int) nmemb,
1424  s5r->domain,
1425  s5r->url);
1426  if (NULL == s5r->response)
1429  if ((SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) &&
1430  (0 == s5r->io_len))
1431  {
1433  "Previous upload finished... starting DOWNLOAD.\n");
1435  }
1436  if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
1437  (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1438  {
1439  /* we're still not done with the upload, do not yet
1440  start the download, the IO buffer is still full
1441  with upload data. */
1443  "Pausing CURL download `%s%s', waiting for UPLOAD to finish\n",
1444  s5r->domain,
1445  s5r->url);
1446  s5r->curl_paused = GNUNET_YES;
1447  return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */
1448  }
1449  if (sizeof(s5r->io_buf) - s5r->io_len < total)
1450  {
1452  "Pausing CURL `%s%s' download, not enough space %llu %llu %llu\n",
1453  s5r->domain,
1454  s5r->url,
1455  (unsigned long long) sizeof(s5r->io_buf),
1456  (unsigned long long) s5r->io_len,
1457  (unsigned long long) total);
1458  s5r->curl_paused = GNUNET_YES;
1459  return CURL_WRITEFUNC_PAUSE; /* not enough space */
1460  }
1461  GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
1462  ptr,
1463  total);
1464  s5r->io_len += total;
1465  if (GNUNET_YES == s5r->suspended)
1466  {
1467  MHD_resume_connection (s5r->con);
1468  s5r->suspended = GNUNET_NO;
1469  }
1471  "Received %llu bytes of payload via cURL from %s\n",
1472  (unsigned long long) total,
1473  s5r->domain);
1474  if (s5r->io_len == total)
1475  run_mhd_now (s5r->hd);
1476  return total;
1477 }
1478 
1479 
1490 static size_t
1492  size_t size,
1493  size_t nmemb,
1494  void *cls)
1495 {
1496  struct Socks5Request *s5r = cls;
1497  size_t len = size * nmemb;
1498  size_t to_copy;
1499 
1501  "Receiving %ux%u bytes for `%s%s' from cURL to upload\n",
1502  (unsigned int) size,
1503  (unsigned int) nmemb,
1504  s5r->domain,
1505  s5r->url);
1506 
1507  if ((0 == s5r->io_len) &&
1508  (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1509  {
1511  "Pausing CURL UPLOAD %s%s, need more data\n",
1512  s5r->domain,
1513  s5r->url);
1514  return CURL_READFUNC_PAUSE;
1515  }
1516  if ((0 == s5r->io_len) &&
1517  (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1518  {
1520  if (GNUNET_YES == s5r->curl_paused)
1521  {
1522  s5r->curl_paused = GNUNET_NO;
1523  curl_easy_pause (s5r->curl,
1524  CURLPAUSE_CONT);
1525  }
1527  "Completed CURL UPLOAD %s%s\n",
1528  s5r->domain,
1529  s5r->url);
1530  return 0; /* upload finished, can now download */
1531  }
1532  if ((SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) &&
1533  (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1534  {
1535  GNUNET_break (0);
1536  return CURL_READFUNC_ABORT;
1537  }
1538  to_copy = GNUNET_MIN (s5r->io_len,
1539  len);
1540  GNUNET_memcpy (buf,
1541  s5r->io_buf,
1542  to_copy);
1543  memmove (s5r->io_buf,
1544  &s5r->io_buf[to_copy],
1545  s5r->io_len - to_copy);
1546  s5r->io_len -= to_copy;
1547  if (s5r->io_len + to_copy == sizeof(s5r->io_buf))
1548  run_mhd_now (s5r->hd); /* got more space for upload now */
1549  return to_copy;
1550 }
1551 
1552 
1553 /* ************************** main loop of cURL interaction ****************** */
1554 
1555 
1562 static void
1563 curl_task_download (void *cls);
1564 
1565 
1569 static void
1571 {
1572  CURLMcode mret;
1573  fd_set rs;
1574  fd_set ws;
1575  fd_set es;
1576  int max;
1577  struct GNUNET_NETWORK_FDSet *grs;
1578  struct GNUNET_NETWORK_FDSet *gws;
1579  long to;
1580  struct GNUNET_TIME_Relative rtime;
1581 
1583  "Scheduling CURL interaction\n");
1584  if (NULL != curl_download_task)
1585  {
1586  GNUNET_SCHEDULER_cancel (curl_download_task);
1587  curl_download_task = NULL;
1588  }
1589  max = -1;
1590  FD_ZERO (&rs);
1591  FD_ZERO (&ws);
1592  FD_ZERO (&es);
1593  if (CURLM_OK != (mret = curl_multi_fdset (curl_multi,
1594  &rs,
1595  &ws,
1596  &es,
1597  &max)))
1598  {
1600  "%s failed at %s:%d: `%s'\n",
1601  "curl_multi_fdset", __FILE__, __LINE__,
1602  curl_multi_strerror (mret));
1603  return;
1604  }
1605  to = -1;
1606  GNUNET_break (CURLM_OK ==
1607  curl_multi_timeout (curl_multi,
1608  &to));
1609  if (-1 == to)
1611  else
1613  to);
1614  if (-1 != max)
1615  {
1616  grs = GNUNET_NETWORK_fdset_create ();
1617  gws = GNUNET_NETWORK_fdset_create ();
1619  &rs,
1620  max + 1);
1622  &ws,
1623  max + 1);
1624  curl_download_task = GNUNET_SCHEDULER_add_select (
1626  rtime,
1627  grs,
1628  gws,
1630  curl_multi);
1633  }
1634  else
1635  {
1636  curl_download_task = GNUNET_SCHEDULER_add_delayed (rtime,
1638  curl_multi);
1639  }
1640 }
1641 
1642 
1648 static void
1650 {
1651  int running;
1652  int msgnum;
1653  struct CURLMsg *msg;
1654  CURLMcode mret;
1655  struct Socks5Request *s5r;
1656 
1657  curl_download_task = NULL;
1659  "Running CURL interaction\n");
1660  do
1661  {
1662  running = 0;
1663  mret = curl_multi_perform (curl_multi,
1664  &running);
1666  "Checking CURL multi status: %d\n",
1667  mret);
1668  while (NULL != (msg = curl_multi_info_read (curl_multi,
1669  &msgnum)))
1670  {
1671  GNUNET_break (CURLE_OK ==
1672  curl_easy_getinfo (msg->easy_handle,
1673  CURLINFO_PRIVATE,
1674  (char **) &s5r));
1675  if (NULL == s5r)
1676  {
1677  GNUNET_break (0);
1678  continue;
1679  }
1680  switch (msg->msg)
1681  {
1682  case CURLMSG_NONE:
1683  /* documentation says this is not used */
1684  GNUNET_break (0);
1685  break;
1686 
1687  case CURLMSG_DONE:
1688  switch (msg->data.result)
1689  {
1690  case CURLE_OK:
1691  case CURLE_GOT_NOTHING:
1693  "CURL download %s%s completed.\n",
1694  s5r->domain,
1695  s5r->url);
1696  if (NULL == s5r->response)
1697  {
1700  }
1701  s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE;
1702  if (GNUNET_YES == s5r->suspended)
1703  {
1704  MHD_resume_connection (s5r->con);
1705  s5r->suspended = GNUNET_NO;
1706  }
1707  run_mhd_now (s5r->hd);
1708  break;
1709 
1710  default:
1712  "Download curl %s%s failed: %s\n",
1713  s5r->domain,
1714  s5r->url,
1715  curl_easy_strerror (msg->data.result));
1716  /* FIXME: indicate error somehow? close MHD connection badly as well? */
1717  s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE;
1718  if (GNUNET_YES == s5r->suspended)
1719  {
1720  MHD_resume_connection (s5r->con);
1721  s5r->suspended = GNUNET_NO;
1722  }
1723  run_mhd_now (s5r->hd);
1724  break;
1725  }
1726  if (NULL == s5r->response)
1727  s5r->response = curl_failure_response;
1728  break;
1729 
1730  case CURLMSG_LAST:
1731  /* documentation says this is not used */
1732  GNUNET_break (0);
1733  break;
1734 
1735  default:
1736  /* unexpected status code */
1737  GNUNET_break (0);
1738  break;
1739  }
1740  }
1741  ;
1742  }
1743  while (mret == CURLM_CALL_MULTI_PERFORM);
1744  if (CURLM_OK != mret)
1746  "%s failed at %s:%d: `%s'\n",
1747  "curl_multi_perform", __FILE__, __LINE__,
1748  curl_multi_strerror (mret));
1749  if (0 == running)
1750  {
1752  "Suspending cURL multi loop, no more events pending\n");
1753  if (NULL != curl_download_task)
1754  {
1755  GNUNET_SCHEDULER_cancel (curl_download_task);
1756  curl_download_task = NULL;
1757  }
1758  return; /* nothing more in progress */
1759  }
1761 }
1762 
1763 
1764 /* ********************************* MHD response generation ******************* */
1765 
1766 
1780 static int
1781 con_val_iter (void *cls,
1782  enum MHD_ValueKind kind,
1783  const char *key,
1784  const char *value)
1785 {
1786  struct Socks5Request *s5r = cls;
1787  char *hdr;
1788 
1789  if ((0 == strcasecmp (MHD_HTTP_HEADER_HOST,
1790  key)) &&
1791  (NULL != s5r->leho))
1792  value = s5r->leho;
1793  GNUNET_asprintf (&hdr,
1794  "%s: %s",
1795  key,
1796  value);
1798  "Adding HEADER `%s' to HTTP request\n",
1799  hdr);
1800  s5r->headers = curl_slist_append (s5r->headers,
1801  hdr);
1802  GNUNET_free (hdr);
1803  return MHD_YES;
1804 }
1805 
1806 
1830 static int
1831 create_response (void *cls,
1832  struct MHD_Connection *con,
1833  const char *url,
1834  const char *meth,
1835  const char *ver,
1836  const char *upload_data,
1837  size_t *upload_data_size,
1838  void **con_cls)
1839 {
1840  struct Socks5Request *s5r = *con_cls;
1841  char *curlurl;
1842  char ipstring[INET6_ADDRSTRLEN];
1843  char ipaddr[INET6_ADDRSTRLEN + 2];
1844  const struct sockaddr *sa;
1845  const struct sockaddr_in *s4;
1846  const struct sockaddr_in6 *s6;
1847  uint16_t port;
1848  size_t left;
1849 
1850  if (NULL == s5r)
1851  {
1852  GNUNET_break (0);
1853  return MHD_NO;
1854  }
1855  s5r->con = con;
1856  /* Fresh connection. */
1857  if (SOCKS5_SOCKET_WITH_MHD == s5r->state)
1858  {
1859  /* first time here, initialize curl handle */
1860  if (s5r->is_gns)
1861  {
1862  sa = (const struct sockaddr *) &s5r->destination_address;
1863  switch (sa->sa_family)
1864  {
1865  case AF_INET:
1866  s4 = (const struct sockaddr_in *) &s5r->destination_address;
1867  if (NULL == inet_ntop (AF_INET,
1868  &s4->sin_addr,
1869  ipstring,
1870  sizeof(ipstring)))
1871  {
1872  GNUNET_break (0);
1873  return MHD_NO;
1874  }
1875  GNUNET_snprintf (ipaddr,
1876  sizeof(ipaddr),
1877  "%s",
1878  ipstring);
1879  port = ntohs (s4->sin_port);
1880  break;
1881 
1882  case AF_INET6:
1883  s6 = (const struct sockaddr_in6 *) &s5r->destination_address;
1884  if (NULL == inet_ntop (AF_INET6,
1885  &s6->sin6_addr,
1886  ipstring,
1887  sizeof(ipstring)))
1888  {
1889  GNUNET_break (0);
1890  return MHD_NO;
1891  }
1892  GNUNET_snprintf (ipaddr,
1893  sizeof(ipaddr),
1894  "%s",
1895  ipstring);
1896  port = ntohs (s6->sin6_port);
1897  break;
1898 
1899  default:
1900  GNUNET_break (0);
1901  return MHD_NO;
1902  }
1903  }
1904  else
1905  {
1906  port = s5r->port;
1907  }
1908  if (NULL == s5r->curl)
1909  s5r->curl = curl_easy_init ();
1910  if (NULL == s5r->curl)
1911  return MHD_queue_response (con,
1912  MHD_HTTP_INTERNAL_SERVER_ERROR,
1914  curl_easy_setopt (s5r->curl,
1915  CURLOPT_HEADERFUNCTION,
1916  &curl_check_hdr);
1917  curl_easy_setopt (s5r->curl,
1918  CURLOPT_HEADERDATA,
1919  s5r);
1920  curl_easy_setopt (s5r->curl,
1921  CURLOPT_FOLLOWLOCATION,
1922  0);
1923  if (s5r->is_gns)
1924  curl_easy_setopt (s5r->curl,
1925  CURLOPT_IPRESOLVE,
1926  CURL_IPRESOLVE_V4);
1927  curl_easy_setopt (s5r->curl,
1928  CURLOPT_CONNECTTIMEOUT,
1929  600L);
1930  curl_easy_setopt (s5r->curl,
1931  CURLOPT_TIMEOUT,
1932  600L);
1933  curl_easy_setopt (s5r->curl,
1934  CURLOPT_NOSIGNAL,
1935  1L);
1936  curl_easy_setopt (s5r->curl,
1937  CURLOPT_HTTP_CONTENT_DECODING,
1938  0);
1939  curl_easy_setopt (s5r->curl,
1940  CURLOPT_NOSIGNAL,
1941  1L);
1942  curl_easy_setopt (s5r->curl,
1943  CURLOPT_PRIVATE,
1944  s5r);
1945  curl_easy_setopt (s5r->curl,
1946  CURLOPT_VERBOSE,
1947  0L);if (NULL != s5r->leho)
1953  {
1954  char *curl_hosts;
1955 
1956  GNUNET_asprintf (&curl_hosts,
1957  "%s:%d:%s",
1958  s5r->leho,
1959  port,
1960  ipaddr);
1961  s5r->hosts = curl_slist_append (NULL,
1962  curl_hosts);
1963  curl_easy_setopt (s5r->curl,
1964  CURLOPT_RESOLVE,
1965  s5r->hosts);
1966  GNUNET_free (curl_hosts);
1967  }
1968  if (s5r->is_gns)
1969  {
1970  GNUNET_asprintf (&curlurl,
1971  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1972  ? "http://%s:%d%s"
1973  : "https://%s:%d%s",
1974  (NULL != s5r->leho)
1975  ? s5r->leho
1976  : ipaddr,
1977  port,
1978  s5r->url);
1979  }
1980  else
1981  {
1982  GNUNET_asprintf (&curlurl,
1983  (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1984  ? "http://%s:%d%s"
1985  : "https://%s:%d%s",
1986  s5r->domain,
1987  port,
1988  s5r->url);
1989  }
1990  curl_easy_setopt (s5r->curl,
1991  CURLOPT_URL,
1992  curlurl);
1994  "Launching %s CURL interaction, fetching `%s'\n",
1995  (s5r->is_gns) ? "GNS" : "DNS",
1996  curlurl);
1997  GNUNET_free (curlurl);
1998  if (0 == strcasecmp (meth,
1999  MHD_HTTP_METHOD_PUT))
2000  {
2002  curl_easy_setopt (s5r->curl,
2003  CURLOPT_UPLOAD,
2004  1L);
2005  curl_easy_setopt (s5r->curl,
2006  CURLOPT_WRITEFUNCTION,
2007  &curl_download_cb);
2008  curl_easy_setopt (s5r->curl,
2009  CURLOPT_WRITEDATA,
2010  s5r);
2011  GNUNET_assert (CURLE_OK ==
2012  curl_easy_setopt (s5r->curl,
2013  CURLOPT_READFUNCTION,
2014  &curl_upload_cb));
2015  curl_easy_setopt (s5r->curl,
2016  CURLOPT_READDATA,
2017  s5r);
2018  {
2019  const char *us;
2020  long upload_size = 0;
2021 
2022  us = MHD_lookup_connection_value (con,
2023  MHD_HEADER_KIND,
2024  MHD_HTTP_HEADER_CONTENT_LENGTH);
2025  if ((1 == sscanf (us,
2026  "%ld",
2027  &upload_size)) &&
2028  (upload_size >= 0))
2029  {
2030  curl_easy_setopt (s5r->curl,
2031  CURLOPT_INFILESIZE,
2032  upload_size);
2033  }
2034  }
2035  }
2036  else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_POST))
2037  {
2039  curl_easy_setopt (s5r->curl,
2040  CURLOPT_POST,
2041  1L);
2042  curl_easy_setopt (s5r->curl,
2043  CURLOPT_WRITEFUNCTION,
2044  &curl_download_cb);
2045  curl_easy_setopt (s5r->curl,
2046  CURLOPT_WRITEDATA,
2047  s5r);
2048  curl_easy_setopt (s5r->curl,
2049  CURLOPT_READFUNCTION,
2050  &curl_upload_cb);
2051  curl_easy_setopt (s5r->curl,
2052  CURLOPT_READDATA,
2053  s5r);
2054  {
2055  const char *us;
2056  long upload_size;
2057 
2058  upload_size = 0;
2059  us = MHD_lookup_connection_value (con,
2060  MHD_HEADER_KIND,
2061  MHD_HTTP_HEADER_CONTENT_LENGTH);
2062  if ((NULL != us) &&
2063  (1 == sscanf (us,
2064  "%ld",
2065  &upload_size)) &&
2066  (upload_size >= 0))
2067  {
2068  curl_easy_setopt (s5r->curl,
2069  CURLOPT_INFILESIZE,
2070  upload_size);
2071  }
2072  else
2073  {
2074  curl_easy_setopt (s5r->curl,
2075  CURLOPT_INFILESIZE,
2076  upload_size);
2077  }
2078  }
2079  }
2080  else if (0 == strcasecmp (meth,
2081  MHD_HTTP_METHOD_HEAD))
2082  {
2084  curl_easy_setopt (s5r->curl,
2085  CURLOPT_NOBODY,
2086  1L);
2087  }
2088  else if (0 == strcasecmp (meth,
2089  MHD_HTTP_METHOD_OPTIONS))
2090  {
2092  curl_easy_setopt (s5r->curl,
2093  CURLOPT_CUSTOMREQUEST,
2094  "OPTIONS");
2095  curl_easy_setopt (s5r->curl,
2096  CURLOPT_WRITEFUNCTION,
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_GET))
2104  {
2106  curl_easy_setopt (s5r->curl,
2107  CURLOPT_HTTPGET,
2108  1L);
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 if (0 == strcasecmp (meth,
2117  MHD_HTTP_METHOD_DELETE))
2118  {
2120  curl_easy_setopt (s5r->curl,
2121  CURLOPT_CUSTOMREQUEST,
2122  "DELETE");
2123  curl_easy_setopt (s5r->curl,
2124  CURLOPT_WRITEFUNCTION,
2125  &curl_download_cb);
2126  curl_easy_setopt (s5r->curl,
2127  CURLOPT_WRITEDATA,
2128  s5r);
2129  }
2130  else
2131  {
2133  _ ("Unsupported HTTP method `%s'\n"),
2134  meth);
2135  curl_easy_cleanup (s5r->curl);
2136  s5r->curl = NULL;
2137  return MHD_NO;
2138  }
2139 
2140  if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_0))
2141  {
2142  curl_easy_setopt (s5r->curl,
2143  CURLOPT_HTTP_VERSION,
2144  CURL_HTTP_VERSION_1_0);
2145  }
2146  else if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_1))
2147  {
2148  curl_easy_setopt (s5r->curl,
2149  CURLOPT_HTTP_VERSION,
2150  CURL_HTTP_VERSION_1_1);
2151  }
2152  else
2153  {
2154  curl_easy_setopt (s5r->curl,
2155  CURLOPT_HTTP_VERSION,
2156  CURL_HTTP_VERSION_NONE);
2157  }
2158 
2159  if (GNUNET_YES == s5r->is_tls) // (HTTPS_PORT == s5r->port)
2160  {
2161  curl_easy_setopt (s5r->curl,
2162  CURLOPT_USE_SSL,
2163  CURLUSESSL_ALL);
2164  if (0 < s5r->num_danes)
2165  curl_easy_setopt (s5r->curl,
2166  CURLOPT_SSL_VERIFYPEER,
2167  0L);
2168  else
2169  curl_easy_setopt (s5r->curl,
2170  CURLOPT_SSL_VERIFYPEER,
2171  1L);
2172  /* Disable cURL checking the hostname, as we will check ourselves
2173  as only we have the domain name or the LEHO or the DANE record */
2174  curl_easy_setopt (s5r->curl,
2175  CURLOPT_SSL_VERIFYHOST,
2176  0L);
2177  }
2178  else
2179  {
2180  curl_easy_setopt (s5r->curl,
2181  CURLOPT_USE_SSL,
2182  CURLUSESSL_NONE);
2183  }
2184 
2185  if (CURLM_OK !=
2186  curl_multi_add_handle (curl_multi,
2187  s5r->curl))
2188  {
2189  GNUNET_break (0);
2190  curl_easy_cleanup (s5r->curl);
2191  s5r->curl = NULL;
2192  return MHD_NO;
2193  }
2194  MHD_get_connection_values (con,
2195  MHD_HEADER_KIND,
2196  (MHD_KeyValueIterator) & con_val_iter,
2197  s5r);
2198  curl_easy_setopt (s5r->curl,
2199  CURLOPT_HTTPHEADER,
2200  s5r->headers);
2202  return MHD_YES;
2203  }
2204 
2205  /* continuing to process request */
2206  if (0 != *upload_data_size)
2207  {
2209  "Processing %u bytes UPLOAD\n",
2210  (unsigned int) *upload_data_size);
2211 
2212  /* FIXME: This must be set or a header with Transfer-Encoding: chunked. Else
2213  * upload callback is not called!
2214  */
2215  curl_easy_setopt (s5r->curl,
2216  CURLOPT_POSTFIELDSIZE,
2217  *upload_data_size);
2218 
2219  left = GNUNET_MIN (*upload_data_size,
2220  sizeof(s5r->io_buf) - s5r->io_len);
2221  GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
2222  upload_data,
2223  left);
2224  s5r->io_len += left;
2225  *upload_data_size -= left;
2226  GNUNET_assert (NULL != s5r->curl);
2227  if (GNUNET_YES == s5r->curl_paused)
2228  {
2229  s5r->curl_paused = GNUNET_NO;
2230  curl_easy_pause (s5r->curl,
2231  CURLPAUSE_CONT);
2232  }
2233  return MHD_YES;
2234  }
2235  if (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state)
2236  {
2238  "Finished processing UPLOAD\n");
2240  }
2241  if (NULL == s5r->response)
2242  {
2244  "Waiting for HTTP response for %s%s...\n",
2245  s5r->domain,
2246  s5r->url);
2247  MHD_suspend_connection (con);
2248  s5r->suspended = GNUNET_YES;
2249  return MHD_YES;
2250  }
2252  "Queueing response for %s%s with MHD\n",
2253  s5r->domain,
2254  s5r->url);
2255  run_mhd_now (s5r->hd);
2256  return MHD_queue_response (con,
2257  s5r->response_code,
2258  s5r->response);
2259 }
2260 
2261 
2262 /* ******************** MHD HTTP setup and event loop ******************** */
2263 
2264 
2274 static void
2275 mhd_completed_cb (void *cls,
2276  struct MHD_Connection *connection,
2277  void **con_cls,
2278  enum MHD_RequestTerminationCode toe)
2279 {
2280  struct Socks5Request *s5r = *con_cls;
2281 
2282  if (NULL == s5r)
2283  return;
2284  if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
2286  "MHD encountered error handling request: %d\n",
2287  toe);
2288  if (NULL != s5r->curl)
2289  {
2291  "Removing cURL handle (MHD interaction complete)\n");
2292  curl_multi_remove_handle (curl_multi,
2293  s5r->curl);
2294  curl_slist_free_all (s5r->headers);
2295  s5r->headers = NULL;
2296  curl_easy_reset (s5r->curl);
2297  s5r->rbuf_len = 0;
2298  s5r->wbuf_len = 0;
2299  s5r->io_len = 0;
2301  }
2302  if ((NULL != s5r->response) &&
2303  (curl_failure_response != s5r->response))
2304  MHD_destroy_response (s5r->response);
2305  for (struct HttpResponseHeader *header = s5r->header_head;
2306  NULL != header;
2307  header = s5r->header_head)
2308  {
2310  s5r->header_tail,
2311  header);
2312  GNUNET_free (header->type);
2313  GNUNET_free (header->value);
2314  GNUNET_free (header);
2315  }
2317  "Finished request for %s\n",
2318  s5r->url);
2319  GNUNET_free (s5r->url);
2321  s5r->url = NULL;
2322  s5r->response = NULL;
2323  *con_cls = NULL;
2324 }
2325 
2326 
2336 static void
2338  struct MHD_Connection *connection,
2339  void **con_cls,
2340  enum MHD_ConnectionNotificationCode cnc)
2341 {
2342  struct Socks5Request *s5r;
2343  const union MHD_ConnectionInfo *ci;
2344  int sock;
2345 
2346  switch (cnc)
2347  {
2348  case MHD_CONNECTION_NOTIFY_STARTED:
2349  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
2350  ci = MHD_get_connection_info (connection,
2351  MHD_CONNECTION_INFO_CONNECTION_FD);
2352  if (NULL == ci)
2353  {
2354  GNUNET_break (0);
2355  return;
2356  }
2357  sock = ci->connect_fd;
2358  for (s5r = s5r_head; NULL != s5r; s5r = s5r->next)
2359  {
2360  if (GNUNET_NETWORK_get_fd (s5r->sock) == sock)
2361  {
2363  "Context set...\n");
2364  s5r->ssl_checked = GNUNET_NO;
2365  *con_cls = s5r;
2366  break;
2367  }
2368  }
2369  break;
2370 
2371  case MHD_CONNECTION_NOTIFY_CLOSED:
2373  "Connection closed... cleaning up\n");
2374  s5r = *con_cls;
2375  if (NULL == s5r)
2376  {
2378  "Connection stale!\n");
2379  return;
2380  }
2381  cleanup_s5r (s5r);
2383  *con_cls = NULL;
2384  break;
2385 
2386  default:
2387  GNUNET_break (0);
2388  }
2389 }
2390 
2391 
2405 static void *
2406 mhd_log_callback (void *cls,
2407  const char *url,
2408  struct MHD_Connection *connection)
2409 {
2410  struct Socks5Request *s5r;
2411  const union MHD_ConnectionInfo *ci;
2412 
2413  ci = MHD_get_connection_info (connection,
2414  MHD_CONNECTION_INFO_SOCKET_CONTEXT);
2415  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
2416  if (NULL == ci)
2417  {
2418  GNUNET_break (0);
2419  return NULL;
2420  }
2421  s5r = ci->socket_context;
2422  if (NULL != s5r->url)
2423  {
2424  GNUNET_break (0);
2425  return NULL;
2426  }
2427  s5r->url = GNUNET_strdup (url);
2428  if (NULL != s5r->timeout_task)
2429  {
2431  s5r->timeout_task = NULL;
2432  }
2434  return s5r;
2435 }
2436 
2437 
2443 static void
2445 {
2446  GNUNET_CONTAINER_DLL_remove (mhd_httpd_head,
2447  mhd_httpd_tail,
2448  hd);
2450  MHD_stop_daemon (hd->daemon);
2451  if (NULL != hd->httpd_task)
2452  {
2454  hd->httpd_task = NULL;
2455  }
2457  if (hd == httpd)
2458  httpd = NULL;
2459  GNUNET_free (hd);
2460 }
2461 
2462 
2468 static void
2469 kill_httpd_task (void *cls)
2470 {
2471  struct MhdHttpList *hd = cls;
2472 
2473  hd->httpd_task = NULL;
2474  kill_httpd (hd);
2475 }
2476 
2477 
2483 static void
2484 do_httpd (void *cls);
2485 
2486 
2494 static void
2496 {
2497  fd_set rs;
2498  fd_set ws;
2499  fd_set es;
2500  struct GNUNET_NETWORK_FDSet *wrs;
2501  struct GNUNET_NETWORK_FDSet *wws;
2502  int max;
2503  int haveto;
2504  MHD_UNSIGNED_LONG_LONG timeout;
2505  struct GNUNET_TIME_Relative tv;
2506 
2507  FD_ZERO (&rs);
2508  FD_ZERO (&ws);
2509  FD_ZERO (&es);
2510  max = -1;
2511  if (MHD_YES !=
2512  MHD_get_fdset (hd->daemon,
2513  &rs,
2514  &ws,
2515  &es,
2516  &max))
2517  {
2518  kill_httpd (hd);
2519  return;
2520  }
2521  haveto = MHD_get_timeout (hd->daemon,
2522  &timeout);
2523  if (MHD_YES == haveto)
2524  tv.rel_value_us = (uint64_t) timeout * 1000LL;
2525  else
2527  if (-1 != max)
2528  {
2529  wrs = GNUNET_NETWORK_fdset_create ();
2530  wws = GNUNET_NETWORK_fdset_create ();
2531  GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
2532  GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
2533  }
2534  else
2535  {
2536  wrs = NULL;
2537  wws = NULL;
2538  }
2539  if (NULL != hd->httpd_task)
2540  {
2542  hd->httpd_task = NULL;
2543  }
2544  if ((MHD_YES != haveto) &&
2545  (-1 == max) &&
2546  (hd != httpd))
2547  {
2548  /* daemon is idle, kill after timeout */
2550  &kill_httpd_task,
2551  hd);
2552  }
2553  else
2554  {
2555  hd->httpd_task =
2557  tv, wrs, wws,
2558  &do_httpd, hd);
2559  }
2560  if (NULL != wrs)
2562  if (NULL != wws)
2564 }
2565 
2566 
2572 static void
2573 do_httpd (void *cls)
2574 {
2575  struct MhdHttpList *hd = cls;
2576 
2577  hd->httpd_task = NULL;
2578  MHD_run (hd->daemon);
2579  schedule_httpd (hd);
2580 }
2581 
2582 
2588 static void
2590 {
2591  if (NULL != hd->httpd_task)
2594  hd);
2595 }
2596 
2597 
2605 static void*
2606 load_file (const char*filename,
2607  unsigned int*size)
2608 {
2609  void *buffer;
2610  uint64_t fsize;
2611 
2612  if (GNUNET_OK !=
2613  GNUNET_DISK_file_size (filename,
2614  &fsize,
2615  GNUNET_YES,
2616  GNUNET_YES))
2617  return NULL;
2618  if (fsize > MAX_PEM_SIZE)
2619  return NULL;
2620  *size = (unsigned int) fsize;
2621  buffer = GNUNET_malloc (*size);
2622  if (fsize !=
2623  GNUNET_DISK_fn_read (filename,
2624  buffer,
2625  (size_t) fsize))
2626  {
2627  GNUNET_free (buffer);
2628  return NULL;
2629  }
2630  return buffer;
2631 }
2632 
2633 
2641 static int
2642 load_key_from_file (gnutls_x509_privkey_t key,
2643  const char*keyfile)
2644 {
2645  gnutls_datum_t key_data;
2646  int ret;
2647 
2648  key_data.data = load_file (keyfile,
2649  &key_data.size);
2650  if (NULL == key_data.data)
2651  return GNUNET_SYSERR;
2652  ret = gnutls_x509_privkey_import (key, &key_data,
2653  GNUTLS_X509_FMT_PEM);
2654  if (GNUTLS_E_SUCCESS != ret)
2655  {
2657  _ ("Unable to import private key from file `%s'\n"),
2658  keyfile);
2659  }
2660  GNUNET_free_non_null (key_data.data);
2661  return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2662 }
2663 
2664 
2672 static int
2673 load_cert_from_file (gnutls_x509_crt_t crt,
2674  const char*certfile)
2675 {
2676  gnutls_datum_t cert_data;
2677  int ret;
2678 
2679  cert_data.data = load_file (certfile,
2680  &cert_data.size);
2681  if (NULL == cert_data.data)
2682  return GNUNET_SYSERR;
2683  ret = gnutls_x509_crt_import (crt,
2684  &cert_data,
2685  GNUTLS_X509_FMT_PEM);
2686  if (GNUTLS_E_SUCCESS != ret)
2687  {
2689  _ ("Unable to import certificate from `%s'\n"),
2690  certfile);
2691  }
2692  GNUNET_free_non_null (cert_data.data);
2693  return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2694 }
2695 
2696 
2703 static struct ProxyGNSCertificate *
2705 {
2706  unsigned int serial;
2707  size_t key_buf_size;
2708  size_t cert_buf_size;
2709  gnutls_x509_crt_t request;
2710  time_t etime;
2711  struct tm *tm_data;
2712  struct ProxyGNSCertificate *pgc;
2713 
2715  "Generating x.509 certificate for `%s'\n",
2716  name);
2717  GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_init (&request));
2718  GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_set_key (request,
2719  proxy_ca.key));
2720  pgc = GNUNET_new (struct ProxyGNSCertificate);
2721  gnutls_x509_crt_set_dn_by_oid (request,
2722  GNUTLS_OID_X520_COUNTRY_NAME,
2723  0,
2724  "ZZ",
2725  strlen ("ZZ"));
2726  gnutls_x509_crt_set_dn_by_oid (request,
2727  GNUTLS_OID_X520_ORGANIZATION_NAME,
2728  0,
2729  "GNU Name System",
2730  strlen ("GNU Name System"));
2731  gnutls_x509_crt_set_dn_by_oid (request,
2732  GNUTLS_OID_X520_COMMON_NAME,
2733  0,
2734  name,
2735  strlen (name));
2736  gnutls_x509_crt_set_subject_alternative_name (request,
2737  GNUTLS_SAN_DNSNAME,
2738  name);
2739  GNUNET_break (GNUTLS_E_SUCCESS ==
2740  gnutls_x509_crt_set_version (request,
2741  3));
2742  gnutls_rnd (GNUTLS_RND_NONCE,
2743  &serial,
2744  sizeof(serial));
2745  gnutls_x509_crt_set_serial (request,
2746  &serial,
2747  sizeof(serial));
2748  etime = time (NULL);
2749  tm_data = localtime (&etime);
2750  tm_data->tm_hour--;
2751  etime = mktime (tm_data);
2752  gnutls_x509_crt_set_activation_time (request,
2753  etime);
2754  tm_data->tm_year++;
2755  etime = mktime (tm_data);
2756  gnutls_x509_crt_set_expiration_time (request,
2757  etime);
2758  gnutls_x509_crt_sign2 (request,
2759  proxy_ca.cert,
2760  proxy_ca.key,
2761  GNUTLS_DIG_SHA512,
2762  0);
2763  key_buf_size = sizeof(pgc->key);
2764  cert_buf_size = sizeof(pgc->cert);
2765  gnutls_x509_crt_export (request,
2766  GNUTLS_X509_FMT_PEM,
2767  pgc->cert,
2768  &cert_buf_size);
2769  gnutls_x509_privkey_export (proxy_ca.key,
2770  GNUTLS_X509_FMT_PEM,
2771  pgc->key,
2772  &key_buf_size);
2773  gnutls_x509_crt_deinit (request);
2774  return pgc;
2775 }
2776 
2777 
2785 static void
2787  const char *fm,
2788  va_list ap)
2789 {
2790  /* do nothing */
2791 }
2792 
2793 
2800 static struct MhdHttpList *
2802 {
2803  struct MhdHttpList *hd;
2804  struct ProxyGNSCertificate *pgc;
2805 
2806  if (NULL == domain)
2807  {
2808  GNUNET_break (0);
2809  return NULL;
2810  }
2811  for (hd = mhd_httpd_head; NULL != hd; hd = hd->next)
2812  if ((NULL != hd->domain) &&
2813  (0 == strcmp (hd->domain, domain)))
2814  return hd;
2816  "Starting fresh MHD HTTPS instance for domain `%s'\n",
2817  domain);
2818  pgc = generate_gns_certificate (domain);
2819  hd = GNUNET_new (struct MhdHttpList);
2820  hd->is_ssl = GNUNET_YES;
2821  hd->domain = GNUNET_strdup (domain);
2822  hd->proxy_cert = pgc;
2823  hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL
2824  | MHD_USE_NO_LISTEN_SOCKET
2825  | MHD_ALLOW_SUSPEND_RESUME,
2826  0,
2827  NULL, NULL,
2828  &create_response, hd,
2829  MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
2830  int) 16,
2831  MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
2832  NULL,
2833  MHD_OPTION_NOTIFY_CONNECTION,
2834  &mhd_connection_cb, NULL,
2835  MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
2836  NULL,
2837  MHD_OPTION_EXTERNAL_LOGGER,
2838  &mhd_error_log_callback, NULL,
2839  MHD_OPTION_HTTPS_MEM_KEY, pgc->key,
2840  MHD_OPTION_HTTPS_MEM_CERT, pgc->cert,
2841  MHD_OPTION_END);
2842  if (NULL == hd->daemon)
2843  {
2844  GNUNET_free (pgc);
2845  GNUNET_free (hd);
2846  return NULL;
2847  }
2848  GNUNET_CONTAINER_DLL_insert (mhd_httpd_head,
2849  mhd_httpd_tail,
2850  hd);
2851  return hd;
2852 }
2853 
2854 
2862 static void
2864 {
2865  struct Socks5Request *s5r = cls;
2866 
2867  s5r->timeout_task = NULL;
2868  cleanup_s5r (s5r);
2869 }
2870 
2871 
2880 static void
2882 {
2883  struct MhdHttpList *hd;
2884  int fd;
2885  const struct sockaddr *addr;
2886  socklen_t len;
2887  char *domain;
2888 
2889  if (GNUNET_YES == s5r->is_tls)
2890  {
2891  GNUNET_asprintf (&domain,
2892  "%s",
2893  s5r->domain);
2894  hd = lookup_ssl_httpd (domain);
2895  if (NULL == hd)
2896  {
2898  _ ("Failed to start HTTPS server for `%s'\n"),
2899  s5r->domain);
2900  cleanup_s5r (s5r);
2901  GNUNET_free (domain);
2902  return;
2903  }
2904  }
2905  else
2906  {
2907  domain = NULL;
2908  GNUNET_assert (NULL != httpd);
2909  hd = httpd;
2910  }
2911  fd = GNUNET_NETWORK_get_fd (s5r->sock);
2912  addr = GNUNET_NETWORK_get_addr (s5r->sock);
2913  len = GNUNET_NETWORK_get_addrlen (s5r->sock);
2915  if (MHD_YES !=
2916  MHD_add_connection (hd->daemon,
2917  fd,
2918  addr,
2919  len))
2920  {
2922  _ ("Failed to pass client to MHD\n"));
2923  cleanup_s5r (s5r);
2924  GNUNET_free_non_null (domain);
2925  return;
2926  }
2927  s5r->hd = hd;
2928  schedule_httpd (hd);
2931  s5r);
2932  GNUNET_free_non_null (domain);
2933 }
2934 
2935 
2936 /* ********************* SOCKS handling ************************* */
2937 
2938 
2944 static void
2945 do_write (void *cls)
2946 {
2947  struct Socks5Request *s5r = cls;
2948  ssize_t len;
2949 
2950  s5r->wtask = NULL;
2951  len = GNUNET_NETWORK_socket_send (s5r->sock,
2952  s5r->wbuf,
2953  s5r->wbuf_len);
2954  if (len <= 0)
2955  {
2956  /* write error: connection closed, shutdown, etc.; just clean up */
2958  "Write Error\n");
2959  cleanup_s5r (s5r);
2960  return;
2961  }
2962  memmove (s5r->wbuf,
2963  &s5r->wbuf[len],
2964  s5r->wbuf_len - len);
2965  s5r->wbuf_len -= len;
2966  if (s5r->wbuf_len > 0)
2967  {
2968  /* not done writing */
2969  s5r->wtask =
2971  s5r->sock,
2972  &do_write, s5r);
2973  return;
2974  }
2975 
2976  /* we're done writing, continue with state machine! */
2977 
2978  switch (s5r->state)
2979  {
2980  case SOCKS5_INIT:
2981  GNUNET_assert (0);
2982  break;
2983 
2984  case SOCKS5_REQUEST:
2985  GNUNET_assert (NULL != s5r->rtask);
2986  break;
2987 
2988  case SOCKS5_DATA_TRANSFER:
2989  setup_data_transfer (s5r);
2990  return;
2991 
2993  cleanup_s5r (s5r);
2994  return;
2995 
2996  default:
2997  GNUNET_break (0);
2998  break;
2999  }
3000 }
3001 
3002 
3009 static void
3011  enum Socks5StatusCode sc)
3012 {
3013  struct Socks5ServerResponseMessage *s_resp;
3014 
3015  s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3016  memset (s_resp, 0, sizeof(struct Socks5ServerResponseMessage));
3017  s_resp->version = SOCKS_VERSION_5;
3018  s_resp->reply = sc;
3020  if (NULL != s5r->wtask)
3021  s5r->wtask =
3023  s5r->sock,
3024  &do_write, s5r);
3025 }
3026 
3027 
3033 static void
3035 {
3036  struct Socks5ServerResponseMessage *s_resp;
3037 
3038  s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3039  s_resp->version = SOCKS_VERSION_5;
3041  s_resp->reserved = 0;
3042  s_resp->addr_type = SOCKS5_AT_IPV4;
3043  /* zero out IPv4 address and port */
3044  memset (&s_resp[1],
3045  0,
3046  sizeof(struct in_addr) + sizeof(uint16_t));
3047  s5r->wbuf_len += sizeof(struct Socks5ServerResponseMessage)
3048  + sizeof(struct in_addr) + sizeof(uint16_t);
3049  if (NULL == s5r->wtask)
3050  s5r->wtask =
3052  s5r->sock,
3053  &do_write, s5r);
3054 }
3055 
3056 
3065 static void
3067  int tld,
3068  uint32_t rd_count,
3069  const struct GNUNET_GNSRECORD_Data *rd)
3070 {
3071  struct Socks5Request *s5r = cls;
3072  const struct GNUNET_GNSRECORD_Data *r;
3073  int got_ip;
3074 
3075  s5r->gns_lookup = NULL;
3076  s5r->is_gns = tld;
3077  got_ip = GNUNET_NO;
3078  for (uint32_t i = 0; i < rd_count; i++)
3079  {
3080  r = &rd[i];
3081  switch (r->record_type)
3082  {
3084  {
3085  struct sockaddr_in *in;
3086 
3087  if (sizeof(struct in_addr) != r->data_size)
3088  {
3089  GNUNET_break_op (0);
3090  break;
3091  }
3092  if (GNUNET_YES == got_ip)
3093  break;
3094  if (GNUNET_OK !=
3095  GNUNET_NETWORK_test_pf (PF_INET))
3096  break;
3097  got_ip = GNUNET_YES;
3098  in = (struct sockaddr_in *) &s5r->destination_address;
3099  in->sin_family = AF_INET;
3100  GNUNET_memcpy (&in->sin_addr,
3101  r->data,
3102  r->data_size);
3103  in->sin_port = htons (s5r->port);
3104 #if HAVE_SOCKADDR_IN_SIN_LEN
3105  in->sin_len = sizeof(*in);
3106 #endif
3107  }
3108  break;
3109 
3111  {
3112  struct sockaddr_in6 *in;
3113 
3114  if (sizeof(struct in6_addr) != r->data_size)
3115  {
3116  GNUNET_break_op (0);
3117  break;
3118  }
3119  if (GNUNET_YES == got_ip)
3120  break;
3121  if (GNUNET_YES == disable_v6)
3122  break;
3123  if (GNUNET_OK !=
3124  GNUNET_NETWORK_test_pf (PF_INET6))
3125  break;
3126  /* FIXME: allow user to disable IPv6 per configuration option... */
3127  got_ip = GNUNET_YES;
3128  in = (struct sockaddr_in6 *) &s5r->destination_address;
3129  in->sin6_family = AF_INET6;
3130  GNUNET_memcpy (&in->sin6_addr,
3131  r->data,
3132  r->data_size);
3133  in->sin6_port = htons (s5r->port);
3134 #if HAVE_SOCKADDR_IN_SIN_LEN
3135  in->sin6_len = sizeof(*in);
3136 #endif
3137  }
3138  break;
3139 
3141  GNUNET_break (0); /* should have been translated within GNS */
3142  break;
3143 
3145  GNUNET_free_non_null (s5r->leho);
3146  s5r->leho = GNUNET_strndup (r->data,
3147  r->data_size);
3148  break;
3149 
3151  {
3152  const struct GNUNET_GNSRECORD_BoxRecord *box;
3153 
3154  if (r->data_size < sizeof(struct GNUNET_GNSRECORD_BoxRecord))
3155  {
3156  GNUNET_break_op (0);
3157  break;
3158  }
3159  box = r->data;
3160  if ((ntohl (box->record_type) != GNUNET_DNSPARSER_TYPE_TLSA) ||
3161  (ntohs (box->protocol) != IPPROTO_TCP) ||
3162  (ntohs (box->service) != s5r->port))
3163  break; /* BOX record does not apply */
3164  if (s5r->num_danes >= MAX_DANES)
3165  {
3166  GNUNET_break (0); /* MAX_DANES too small */
3167  break;
3168  }
3169  s5r->is_tls = GNUNET_YES; /* This should be TLS */
3170  s5r->dane_data_len[s5r->num_danes]
3171  = r->data_size - sizeof(struct GNUNET_GNSRECORD_BoxRecord);
3172  s5r->dane_data[s5r->num_danes]
3173  = GNUNET_memdup (&box[1],
3174  s5r->dane_data_len[s5r->num_danes]);
3175  s5r->num_danes++;
3176  break;
3177  }
3178 
3179  default:
3180  /* don't care */
3181  break;
3182  }
3183  }
3184  if ((GNUNET_YES != got_ip) &&
3185  (GNUNET_YES == tld))
3186  {
3188  "Name resolution failed to yield useful IP address.\n");
3189  signal_socks_failure (s5r,
3191  return;
3192  }
3193  s5r->state = SOCKS5_DATA_TRANSFER;
3194  signal_socks_success (s5r);
3195 }
3196 
3197 
3204 static void
3206  size_t len)
3207 {
3208  GNUNET_assert (len <= s5r->rbuf_len);
3209  memmove (s5r->rbuf,
3210  &s5r->rbuf[len],
3211  s5r->rbuf_len - len);
3212  s5r->rbuf_len -= len;
3213 }
3214 
3215 
3221 static void
3222 do_s5r_read (void *cls)
3223 {
3224  struct Socks5Request *s5r = cls;
3225  const struct Socks5ClientHelloMessage *c_hello;
3226  struct Socks5ServerHelloMessage *s_hello;
3227  const struct Socks5ClientRequestMessage *c_req;
3228  ssize_t rlen;
3229  size_t alen;
3230  const struct GNUNET_SCHEDULER_TaskContext *tc;
3231 
3232  s5r->rtask = NULL;
3234  if ((NULL != tc->read_ready) &&
3236  s5r->sock)))
3237  {
3238  rlen = GNUNET_NETWORK_socket_recv (s5r->sock,
3239  &s5r->rbuf[s5r->rbuf_len],
3240  sizeof(s5r->rbuf) - s5r->rbuf_len);
3241  if (rlen <= 0)
3242  {
3244  "socks5 client disconnected.\n");
3245  cleanup_s5r (s5r);
3246  return;
3247  }
3248  s5r->rbuf_len += rlen;
3249  }
3251  s5r->sock,
3252  &do_s5r_read, s5r);
3254  "Processing %zu bytes of socks data in state %d\n",
3255  s5r->rbuf_len,
3256  s5r->state);
3257  switch (s5r->state)
3258  {
3259  case SOCKS5_INIT:
3260  c_hello = (const struct Socks5ClientHelloMessage*) &s5r->rbuf;
3261  if ((s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)) ||
3262  (s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)
3263  + c_hello->num_auth_methods))
3264  return; /* need more data */
3265  if (SOCKS_VERSION_5 != c_hello->version)
3266  {
3268  _ ("Unsupported socks version %d\n"),
3269  (int) c_hello->version);
3270  cleanup_s5r (s5r);
3271  return;
3272  }
3273  clear_from_s5r_rbuf (s5r,
3274  sizeof(struct Socks5ClientHelloMessage)
3275  + c_hello->num_auth_methods);
3276  GNUNET_assert (0 == s5r->wbuf_len);
3277  s_hello = (struct Socks5ServerHelloMessage *) &s5r->wbuf;
3278  s5r->wbuf_len = sizeof(struct Socks5ServerHelloMessage);
3279  s_hello->version = SOCKS_VERSION_5;
3280  s_hello->auth_method = SOCKS_AUTH_NONE;
3281  GNUNET_assert (NULL == s5r->wtask);
3283  s5r->sock,
3284  &do_write, s5r);
3285  s5r->state = SOCKS5_REQUEST;
3286  return;
3287 
3288  case SOCKS5_REQUEST:
3289  c_req = (const struct Socks5ClientRequestMessage *) &s5r->rbuf;
3290  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage))
3291  return;
3292  switch (c_req->command)
3293  {
3294  case SOCKS5_CMD_TCP_STREAM:
3295  /* handled below */
3296  break;
3297 
3298  default:
3300  _ ("Unsupported socks command %d\n"),
3301  (int) c_req->command);
3302  signal_socks_failure (s5r,
3304  return;
3305  }
3306  switch (c_req->addr_type)
3307  {
3308  case SOCKS5_AT_IPV4:
3309  {
3310  const struct in_addr *v4 = (const struct in_addr *) &c_req[1];
3311  const uint16_t *port = (const uint16_t *) &v4[1];
3312  struct sockaddr_in *in;
3313 
3314  s5r->port = ntohs (*port);
3315  alen = sizeof(struct in_addr);
3316  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3317  + alen + sizeof(uint16_t))
3318  return; /* need more data */
3319  in = (struct sockaddr_in *) &s5r->destination_address;
3320  in->sin_family = AF_INET;
3321  in->sin_addr = *v4;
3322  in->sin_port = *port;
3323 #if HAVE_SOCKADDR_IN_SIN_LEN
3324  in->sin_len = sizeof(*in);
3325 #endif
3326  s5r->state = SOCKS5_DATA_TRANSFER;
3327  }
3328  break;
3329 
3330  case SOCKS5_AT_IPV6:
3331  {
3332  const struct in6_addr *v6 = (const struct in6_addr *) &c_req[1];
3333  const uint16_t *port = (const uint16_t *) &v6[1];
3334  struct sockaddr_in6 *in;
3335 
3336  s5r->port = ntohs (*port);
3337  alen = sizeof(struct in6_addr);
3338  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3339  + alen + sizeof(uint16_t))
3340  return; /* need more data */
3341  in = (struct sockaddr_in6 *) &s5r->destination_address;
3342  in->sin6_family = AF_INET6;
3343  in->sin6_addr = *v6;
3344  in->sin6_port = *port;
3345 #if HAVE_SOCKADDR_IN_SIN_LEN
3346  in->sin6_len = sizeof(*in);
3347 #endif
3348  s5r->state = SOCKS5_DATA_TRANSFER;
3349  }
3350  break;
3351 
3352  case SOCKS5_AT_DOMAINNAME:
3353  {
3354  const uint8_t *dom_len;
3355  const char *dom_name;
3356  const uint16_t *port;
3357 
3358  dom_len = (const uint8_t *) &c_req[1];
3359  alen = *dom_len + 1;
3360  if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3361  + alen + sizeof(uint16_t))
3362  return; /* need more data */
3363  dom_name = (const char *) &dom_len[1];
3364  port = (const uint16_t*) &dom_name[*dom_len];
3365  s5r->domain = GNUNET_strndup (dom_name,
3366  *dom_len);
3368  "Requested connection is to %s:%d\n",
3369  // (HTTPS_PORT == s5r->port) ? "s" : "",
3370  s5r->domain,
3371  ntohs (*port));
3372  s5r->state = SOCKS5_RESOLVING;
3373  s5r->port = ntohs (*port);
3374  s5r->is_tls = (HTTPS_PORT == s5r->port) ? GNUNET_YES : GNUNET_NO;
3375  s5r->gns_lookup = GNUNET_GNS_lookup_with_tld (gns_handle,
3376  s5r->domain,
3378  GNUNET_NO /* only cached */,
3380  s5r);
3381  break;
3382  }
3383 
3384  default:
3386  _ ("Unsupported socks address type %d\n"),
3387  (int) c_req->addr_type);
3388  signal_socks_failure (s5r,
3390  return;
3391  }
3392  clear_from_s5r_rbuf (s5r,
3393  sizeof(struct Socks5ClientRequestMessage)
3394  + alen + sizeof(uint16_t));
3395  if (0 != s5r->rbuf_len)
3396  {
3397  /* read more bytes than healthy, why did the client send more!? */
3398  GNUNET_break_op (0);
3399  signal_socks_failure (s5r,
3401  return;
3402  }
3403  if (SOCKS5_DATA_TRANSFER == s5r->state)
3404  {
3405  /* if we are not waiting for GNS resolution, signal success */
3406  signal_socks_success (s5r);
3407  }
3408  /* We are done reading right now */
3410  s5r->rtask = NULL;
3411  return;
3412 
3413  case SOCKS5_RESOLVING:
3414  GNUNET_assert (0);
3415  return;
3416 
3417  case SOCKS5_DATA_TRANSFER:
3418  GNUNET_assert (0);
3419  return;
3420 
3421  default:
3422  GNUNET_assert (0);
3423  return;
3424  }
3425 }
3426 
3427 
3434 static void
3435 do_accept (void *cls)
3436 {
3437  struct GNUNET_NETWORK_Handle *lsock = cls;
3438  struct GNUNET_NETWORK_Handle *s;
3439  struct Socks5Request *s5r;
3440 
3441  GNUNET_assert (NULL != lsock);
3442  if (lsock == lsock4)
3444  lsock,
3445  &do_accept,
3446  lsock);
3447  else if (lsock == lsock6)
3449  lsock,
3450  &do_accept,
3451  lsock);
3452  else
3453  GNUNET_assert (0);
3454  s = GNUNET_NETWORK_socket_accept (lsock,
3455  NULL,
3456  NULL);
3457  if (NULL == s)
3458  {
3460  "accept");
3461  return;
3462  }
3464  "Got an inbound connection, waiting for data\n");
3465  s5r = GNUNET_new (struct Socks5Request);
3466  GNUNET_CONTAINER_DLL_insert (s5r_head,
3467  s5r_tail,
3468  s5r);
3469  s5r->sock = s;
3470  s5r->state = SOCKS5_INIT;
3472  s5r->sock,
3473  &do_s5r_read,
3474  s5r);
3475 }
3476 
3477 
3478 /* ******************* General / main code ********************* */
3479 
3480 
3486 static void
3487 do_shutdown (void *cls)
3488 {
3490  "Shutting down...\n");
3491  /* MHD requires resuming before destroying the daemons */
3492  for (struct Socks5Request *s5r = s5r_head;
3493  NULL != s5r;
3494  s5r = s5r->next)
3495  {
3496  if (s5r->suspended)
3497  {
3498  s5r->suspended = GNUNET_NO;
3499  MHD_resume_connection (s5r->con);
3500  }
3501  }
3502  while (NULL != mhd_httpd_head)
3503  kill_httpd (mhd_httpd_head);
3504  while (NULL != s5r_head)
3505  cleanup_s5r (s5r_head);
3506  if (NULL != lsock4)
3507  {
3508  GNUNET_NETWORK_socket_close (lsock4);
3509  lsock4 = NULL;
3510  }
3511  if (NULL != lsock6)
3512  {
3513  GNUNET_NETWORK_socket_close (lsock6);
3514  lsock6 = NULL;
3515  }
3516  if (NULL != curl_multi)
3517  {
3518  curl_multi_cleanup (curl_multi);
3519  curl_multi = NULL;
3520  }
3521  if (NULL != gns_handle)
3522  {
3523  GNUNET_GNS_disconnect (gns_handle);
3524  gns_handle = NULL;
3525  }
3526  if (NULL != curl_download_task)
3527  {
3528  GNUNET_SCHEDULER_cancel (curl_download_task);
3529  curl_download_task = NULL;
3530  }
3531  if (NULL != ltask4)
3532  {
3533  GNUNET_SCHEDULER_cancel (ltask4);
3534  ltask4 = NULL;
3535  }
3536  if (NULL != ltask6)
3537  {
3538  GNUNET_SCHEDULER_cancel (ltask6);
3539  ltask6 = NULL;
3540  }
3541  gnutls_x509_crt_deinit (proxy_ca.cert);
3542  gnutls_x509_privkey_deinit (proxy_ca.key);
3543  gnutls_global_deinit ();
3544 }
3545 
3546 
3552 static struct GNUNET_NETWORK_Handle *
3554 {
3555  struct GNUNET_NETWORK_Handle *ls;
3556  struct sockaddr_in sa4;
3557  int eno;
3558 
3559  memset (&sa4, 0, sizeof(sa4));
3560  sa4.sin_family = AF_INET;
3561  sa4.sin_port = htons (port);
3562  sa4.sin_addr.s_addr = address;
3563 #if HAVE_SOCKADDR_IN_SIN_LEN
3564  sa4.sin_len = sizeof(sa4);
3565 #endif
3566  ls = GNUNET_NETWORK_socket_create (AF_INET,
3567  SOCK_STREAM,
3568  0);
3569  if (NULL == ls)
3570  return NULL;
3571  if (GNUNET_OK !=
3573  (const struct sockaddr *) &sa4,
3574  sizeof(sa4)))
3575  {
3576  eno = errno;
3578  errno = eno;
3579  return NULL;
3580  }
3581  return ls;
3582 }
3583 
3584 
3590 static struct GNUNET_NETWORK_Handle *
3592 {
3593  struct GNUNET_NETWORK_Handle *ls;
3594  struct sockaddr_in6 sa6;
3595  int eno;
3596 
3597  memset (&sa6, 0, sizeof(sa6));
3598  sa6.sin6_family = AF_INET6;
3599  sa6.sin6_port = htons (port);
3600  sa6.sin6_addr = address6;
3601 #if HAVE_SOCKADDR_IN_SIN_LEN
3602  sa6.sin6_len = sizeof(sa6);
3603 #endif
3604  ls = GNUNET_NETWORK_socket_create (AF_INET6,
3605  SOCK_STREAM,
3606  0);
3607  if (NULL == ls)
3608  return NULL;
3609  if (GNUNET_OK !=
3611  (const struct sockaddr *) &sa6,
3612  sizeof(sa6)))
3613  {
3614  eno = errno;
3616  errno = eno;
3617  return NULL;
3618  }
3619  return ls;
3620 }
3621 
3622 
3631 static void
3632 run (void *cls,
3633  char *const *args,
3634  const char *cfgfile,
3635  const struct GNUNET_CONFIGURATION_Handle *c)
3636 {
3637  char*cafile_cfg = NULL;
3638  char*cafile;
3639  char*addr_str;
3640  struct MhdHttpList *hd;
3641 
3642  cfg = c;
3643 
3644  /* Get address to bind to */
3645  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "gns-proxy",
3646  "BIND_TO",
3647  &addr_str))
3648  {
3649  // No address specified
3651  "Don't know what to bind to...\n");
3652  GNUNET_free (addr_str);
3654  return;
3655  }
3656  if (1 != inet_pton (AF_INET, addr_str, &address))
3657  {
3659  "Unable to parse address %s\n",
3660  addr_str);
3661  GNUNET_free (addr_str);
3663  return;
3664  }
3665  GNUNET_free (addr_str);
3666  /* Get address to bind to */
3667  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "gns-proxy",
3668  "BIND_TO6",
3669  &addr_str))
3670  {
3671  // No address specified
3673  "Don't know what to bind6 to...\n");
3674  GNUNET_free (addr_str);
3676  return;
3677  }
3678  if (1 != inet_pton (AF_INET6, addr_str, &address6))
3679  {
3681  "Unable to parse IPv6 address %s\n",
3682  addr_str);
3683  GNUNET_free (addr_str);
3685  return;
3686  }
3687  GNUNET_free (addr_str);
3688 
3689  if (NULL == (curl_multi = curl_multi_init ()))
3690  {
3692  "Failed to create cURL multi handle!\n");
3693  return;
3694  }
3695  cafile = cafile_opt;
3696  if (NULL == cafile)
3697  {
3698  if (GNUNET_OK !=
3700  "gns-proxy",
3701  "PROXY_CACERT",
3702  &cafile_cfg))
3703  {
3705  "gns-proxy",
3706  "PROXY_CACERT");
3707  return;
3708  }
3709  cafile = cafile_cfg;
3710  }
3712  "Using `%s' as CA\n",
3713  cafile);
3714 
3715  gnutls_global_init ();
3716  gnutls_x509_crt_init (&proxy_ca.cert);
3717  gnutls_x509_privkey_init (&proxy_ca.key);
3718 
3719  if ((GNUNET_OK !=
3721  cafile)) ||
3722  (GNUNET_OK !=
3724  cafile)))
3725  {
3727  _ ("Failed to load X.509 key and certificate from `%s'\n"),
3728  cafile);
3729  gnutls_x509_crt_deinit (proxy_ca.cert);
3730  gnutls_x509_privkey_deinit (proxy_ca.key);
3731  gnutls_global_deinit ();
3732  GNUNET_free_non_null (cafile_cfg);
3733  return;
3734  }
3735  GNUNET_free_non_null (cafile_cfg);
3736  if (NULL == (gns_handle = GNUNET_GNS_connect (cfg)))
3737  {
3739  "Unable to connect to GNS!\n");
3740  gnutls_x509_crt_deinit (proxy_ca.cert);
3741  gnutls_x509_privkey_deinit (proxy_ca.key);
3742  gnutls_global_deinit ();
3743  return;
3744  }
3746  NULL);
3747 
3748  /* Open listen socket for socks proxy */
3749  lsock6 = bind_v6 ();
3750  if (NULL == lsock6)
3751  {
3753  "bind");
3754  }
3755  else
3756  {
3757  if (GNUNET_OK !=
3759  5))
3760  {
3762  "listen");
3763  GNUNET_NETWORK_socket_close (lsock6);
3764  lsock6 = NULL;
3765  }
3766  else
3767  {
3769  lsock6,
3770  &do_accept,
3771  lsock6);
3772  }
3773  }
3774  lsock4 = bind_v4 ();
3775  if (NULL == lsock4)
3776  {
3778  "bind");
3779  }
3780  else
3781  {
3782  if (GNUNET_OK !=
3784  5))
3785  {
3787  "listen");
3788  GNUNET_NETWORK_socket_close (lsock4);
3789  lsock4 = NULL;
3790  }
3791  else
3792  {
3794  lsock4,
3795  &do_accept,
3796  lsock4);
3797  }
3798  }
3799  if ((NULL == lsock4) &&
3800  (NULL == lsock6))
3801  {
3803  return;
3804  }
3805  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
3806  {
3808  "cURL global init failed!\n");
3810  return;
3811  }
3813  "Proxy listens on port %u\n",
3814  (unsigned int) port);
3815 
3816  /* start MHD daemon for HTTP */
3817  hd = GNUNET_new (struct MhdHttpList);
3818  hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
3819  | MHD_ALLOW_SUSPEND_RESUME,
3820  0,
3821  NULL, NULL,
3822  &create_response, hd,
3823  MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
3824  int) 16,
3825  MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
3826  NULL,
3827  MHD_OPTION_NOTIFY_CONNECTION,
3828  &mhd_connection_cb, NULL,
3829  MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
3830  NULL,
3831  MHD_OPTION_END);
3832  if (NULL == hd->daemon)
3833  {
3834  GNUNET_free (hd);
3836  return;
3837  }
3838  httpd = hd;
3839  GNUNET_CONTAINER_DLL_insert (mhd_httpd_head,
3840  mhd_httpd_tail,
3841  hd);
3842 }
3843 
3844 
3852 int
3853 main (int argc,
3854  char *const *argv)
3855 {
3856  struct GNUNET_GETOPT_CommandLineOption options[] = {
3858  "port",
3859  NULL,
3860  gettext_noop (
3861  "listen on specified port (default: 7777)"),
3862  &port),
3864  "authority",
3865  NULL,
3866  gettext_noop ("pem file to use as CA"),
3867  &cafile_opt),
3869  "disable-ivp6",
3870  gettext_noop ("disable use of IPv6"),
3871  &disable_v6),
3872 
3874  };
3875  static const char*page =
3876  "<html><head><title>gnunet-gns-proxy</title>"
3877  "</head><body>cURL fail</body></html>";
3878  int ret;
3879 
3880  if (GNUNET_OK !=
3881  GNUNET_STRINGS_get_utf8_args (argc, argv,
3882  &argc, &argv))
3883  return 2;
3884  GNUNET_log_setup ("gnunet-gns-proxy",
3885  "WARNING",
3886  NULL);
3888  = MHD_create_response_from_buffer (strlen (page),
3889  (void *) page,
3890  MHD_RESPMEM_PERSISTENT);
3891 
3892  ret =
3893  (GNUNET_OK ==
3894  GNUNET_PROGRAM_run (argc, argv,
3895  "gnunet-gns-proxy",
3896  _ ("GNUnet GNS proxy"),
3897  options,
3898  &run, NULL)) ? 0 : 1;
3899  MHD_destroy_response (curl_failure_response);
3900  GNUNET_free_non_null ((char *) argv);
3901  return ret;
3902 }
3903 
3904 
3905 /* 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:708
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:747
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition: network.c:1080
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:1093
#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:816
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:1106
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:1300
void * GNUNET_GNS_lookup_with_tld_cancel(struct GNUNET_GNS_LookupWithTldRequest *ltr)
Cancel pending lookup request.
Definition: gns_tld_api.c:329
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:787
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:1438
#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:418
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:485
struct GNUNET_GNS_LookupWithTldRequest * GNUNET_GNS_lookup_with_tld(struct GNUNET_GNS_Handle *handle, const char *name, uint32_t type, enum GNUNET_GNS_LocalOptions options, GNUNET_GNS_LookupResultProcessor2 proc, void *proc_cls)
Perform an asynchronous lookup operation on the GNS, determining the zone using the TLD of the given ...
Definition: gns_tld_api.c:241
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:1557
#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.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
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:526
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:1120
#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:622
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:430
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:1266
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:1253
#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:1250
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 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
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
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:1280
void GNUNET_GNS_disconnect(struct GNUNET_GNS_Handle *handle)
Shutdown connection with the GNS service.
Definition: gns_api.c:284
#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:1810
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:442
#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:262
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.
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:67
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.
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:257
#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:85
const char * name
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:134
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:52
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:1486
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.
static uint64_t etime
Expiration string converted to numeric value.
Definition: gnunet-abd.c:201
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:1029
static int verify
Verify mode.
Definition: gnunet-abd.c:127
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:560
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:794
int GNUNET_NETWORK_test_pf(int pf)
Test if the given protocol family is supported by this system.
Definition: network.c:85
#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:912
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:966