Reseed.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. #include <string.h>
  2. #include <fstream>
  3. #include <sstream>
  4. #include <boost/asio.hpp>
  5. #include <boost/asio/ssl.hpp>
  6. #include <boost/algorithm/string.hpp>
  7. #include <openssl/ssl.h>
  8. #include <openssl/err.h>
  9. #include <zlib.h>
  10. #include "Crypto.h"
  11. #include "I2PEndian.h"
  12. #include "Reseed.h"
  13. #include "FS.h"
  14. #include "Log.h"
  15. #include "Identity.h"
  16. #include "NetDb.hpp"
  17. #include "HTTP.h"
  18. #include "util.h"
  19. #include "Config.h"
  20. namespace i2p
  21. {
  22. namespace data
  23. {
  24. Reseeder::Reseeder()
  25. {
  26. }
  27. Reseeder::~Reseeder()
  28. {
  29. }
  30. /** @brief tries to bootstrap into I2P network (from local files and servers, with respect of options)
  31. */
  32. void Reseeder::Bootstrap ()
  33. {
  34. std::string su3FileName; i2p::config::GetOption("reseed.file", su3FileName);
  35. std::string zipFileName; i2p::config::GetOption("reseed.zipfile", zipFileName);
  36. if (su3FileName.length() > 0) // bootstrap from SU3 file or URL
  37. {
  38. int num;
  39. if (su3FileName.length() > 8 && su3FileName.substr(0, 8) == "https://")
  40. {
  41. num = ReseedFromSU3Url (su3FileName); // from https URL
  42. }
  43. else
  44. {
  45. num = ProcessSU3File (su3FileName.c_str ());
  46. }
  47. if (num == 0)
  48. LogPrint (eLogWarning, "Reseed: failed to reseed from ", su3FileName);
  49. }
  50. else if (zipFileName.length() > 0) // bootstrap from ZIP file
  51. {
  52. int num = ProcessZIPFile (zipFileName.c_str ());
  53. if (num == 0)
  54. LogPrint (eLogWarning, "Reseed: failed to reseed from ", zipFileName);
  55. }
  56. else // bootstrap from reseed servers
  57. {
  58. int num = ReseedFromServers ();
  59. if (num == 0)
  60. LogPrint (eLogWarning, "Reseed: failed to reseed from servers");
  61. }
  62. }
  63. /** @brief bootstrap from random server, retry 10 times
  64. * @return number of entries added to netDb
  65. */
  66. int Reseeder::ReseedFromServers ()
  67. {
  68. std::string reseedURLs; i2p::config::GetOption("reseed.urls", reseedURLs);
  69. std::vector<std::string> httpsReseedHostList;
  70. boost::split(httpsReseedHostList, reseedURLs, boost::is_any_of(","), boost::token_compress_on);
  71. if (reseedURLs.length () == 0)
  72. {
  73. LogPrint (eLogWarning, "Reseed: No reseed servers specified");
  74. return 0;
  75. }
  76. int reseedRetries = 0;
  77. while (reseedRetries < 10)
  78. {
  79. auto ind = rand () % httpsReseedHostList.size ();
  80. std::string reseedUrl = httpsReseedHostList[ind] + "i2pseeds.su3";
  81. auto num = ReseedFromSU3Url (reseedUrl);
  82. if (num > 0) return num; // success
  83. reseedRetries++;
  84. }
  85. LogPrint (eLogWarning, "Reseed: failed to reseed from servers after 10 attempts");
  86. return 0;
  87. }
  88. /** @brief bootstrap from HTTPS URL with SU3 file
  89. * @param url
  90. * @return number of entries added to netDb
  91. */
  92. int Reseeder::ReseedFromSU3Url (const std::string& url)
  93. {
  94. LogPrint (eLogInfo, "Reseed: Downloading SU3 from ", url);
  95. std::string su3 = HttpsRequest (url);
  96. if (su3.length () > 0)
  97. {
  98. std::stringstream s(su3);
  99. return ProcessSU3Stream (s);
  100. }
  101. else
  102. {
  103. LogPrint (eLogWarning, "Reseed: SU3 download failed");
  104. return 0;
  105. }
  106. }
  107. int Reseeder::ProcessSU3File (const char * filename)
  108. {
  109. std::ifstream s(filename, std::ifstream::binary);
  110. if (s.is_open ())
  111. return ProcessSU3Stream (s);
  112. else
  113. {
  114. LogPrint (eLogError, "Reseed: Can't open file ", filename);
  115. return 0;
  116. }
  117. }
  118. int Reseeder::ProcessZIPFile (const char * filename)
  119. {
  120. std::ifstream s(filename, std::ifstream::binary);
  121. if (s.is_open ())
  122. {
  123. s.seekg (0, std::ios::end);
  124. auto len = s.tellg ();
  125. s.seekg (0, std::ios::beg);
  126. return ProcessZIPStream (s, len);
  127. }
  128. else
  129. {
  130. LogPrint (eLogError, "Reseed: Can't open file ", filename);
  131. return 0;
  132. }
  133. }
  134. const char SU3_MAGIC_NUMBER[]="I2Psu3";
  135. int Reseeder::ProcessSU3Stream (std::istream& s)
  136. {
  137. char magicNumber[7];
  138. s.read (magicNumber, 7); // magic number and zero byte 6
  139. if (strcmp (magicNumber, SU3_MAGIC_NUMBER))
  140. {
  141. LogPrint (eLogError, "Reseed: Unexpected SU3 magic number");
  142. return 0;
  143. }
  144. s.seekg (1, std::ios::cur); // su3 file format version
  145. SigningKeyType signatureType;
  146. s.read ((char *)&signatureType, 2); // signature type
  147. signatureType = be16toh (signatureType);
  148. uint16_t signatureLength;
  149. s.read ((char *)&signatureLength, 2); // signature length
  150. signatureLength = be16toh (signatureLength);
  151. s.seekg (1, std::ios::cur); // unused
  152. uint8_t versionLength;
  153. s.read ((char *)&versionLength, 1); // version length
  154. s.seekg (1, std::ios::cur); // unused
  155. uint8_t signerIDLength;
  156. s.read ((char *)&signerIDLength, 1); // signer ID length
  157. uint64_t contentLength;
  158. s.read ((char *)&contentLength, 8); // content length
  159. contentLength = be64toh (contentLength);
  160. s.seekg (1, std::ios::cur); // unused
  161. uint8_t fileType;
  162. s.read ((char *)&fileType, 1); // file type
  163. if (fileType != 0x00) // zip file
  164. {
  165. LogPrint (eLogError, "Reseed: Can't handle file type ", (int)fileType);
  166. return 0;
  167. }
  168. s.seekg (1, std::ios::cur); // unused
  169. uint8_t contentType;
  170. s.read ((char *)&contentType, 1); // content type
  171. if (contentType != 0x03) // reseed data
  172. {
  173. LogPrint (eLogError, "Reseed: Unexpected content type ", (int)contentType);
  174. return 0;
  175. }
  176. s.seekg (12, std::ios::cur); // unused
  177. s.seekg (versionLength, std::ios::cur); // skip version
  178. char signerID[256];
  179. s.read (signerID, signerIDLength); // signerID
  180. signerID[signerIDLength] = 0;
  181. bool verify; i2p::config::GetOption("reseed.verify", verify);
  182. if (verify)
  183. {
  184. //try to verify signature
  185. auto it = m_SigningKeys.find (signerID);
  186. if (it != m_SigningKeys.end ())
  187. {
  188. // TODO: implement all signature types
  189. if (signatureType == SIGNING_KEY_TYPE_RSA_SHA512_4096)
  190. {
  191. size_t pos = s.tellg ();
  192. size_t tbsLen = pos + contentLength;
  193. uint8_t * tbs = new uint8_t[tbsLen];
  194. s.seekg (0, std::ios::beg);
  195. s.read ((char *)tbs, tbsLen);
  196. uint8_t * signature = new uint8_t[signatureLength];
  197. s.read ((char *)signature, signatureLength);
  198. // RSA-raw
  199. {
  200. // calculate digest
  201. uint8_t digest[64];
  202. SHA512 (tbs, tbsLen, digest);
  203. // encrypt signature
  204. BN_CTX * bnctx = BN_CTX_new ();
  205. BIGNUM * s = BN_new (), * n = BN_new ();
  206. BN_bin2bn (signature, signatureLength, s);
  207. BN_bin2bn (it->second, 512, n); // RSA 4096 assumed
  208. BN_mod_exp (s, s, i2p::crypto::GetRSAE (), n, bnctx); // s = s^e mod n
  209. uint8_t * enSigBuf = new uint8_t[signatureLength];
  210. i2p::crypto::bn2buf (s, enSigBuf, signatureLength);
  211. // digest is right aligned
  212. // we can't use RSA_verify due wrong padding in SU3
  213. if (memcmp (enSigBuf + (signatureLength - 64), digest, 64))
  214. LogPrint (eLogWarning, "Reseed: SU3 signature verification failed");
  215. else
  216. verify = false; // verified
  217. delete[] enSigBuf;
  218. BN_free (s); BN_free (n);
  219. BN_CTX_free (bnctx);
  220. }
  221. delete[] signature;
  222. delete[] tbs;
  223. s.seekg (pos, std::ios::beg);
  224. }
  225. else
  226. LogPrint (eLogWarning, "Reseed: Signature type ", signatureType, " is not supported");
  227. }
  228. else
  229. LogPrint (eLogWarning, "Reseed: Certificate for ", signerID, " not loaded");
  230. }
  231. if (verify) // not verified
  232. {
  233. LogPrint (eLogError, "Reseed: SU3 verification failed");
  234. return 0;
  235. }
  236. // handle content
  237. return ProcessZIPStream (s, contentLength);
  238. }
  239. const uint32_t ZIP_HEADER_SIGNATURE = 0x04034B50;
  240. const uint32_t ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE = 0x02014B50;
  241. const uint16_t ZIP_BIT_FLAG_DATA_DESCRIPTOR = 0x0008;
  242. int Reseeder::ProcessZIPStream (std::istream& s, uint64_t contentLength)
  243. {
  244. int numFiles = 0;
  245. size_t contentPos = s.tellg ();
  246. while (!s.eof ())
  247. {
  248. uint32_t signature;
  249. s.read ((char *)&signature, 4);
  250. signature = le32toh (signature);
  251. if (signature == ZIP_HEADER_SIGNATURE)
  252. {
  253. // next local file
  254. s.seekg (2, std::ios::cur); // version
  255. uint16_t bitFlag;
  256. s.read ((char *)&bitFlag, 2);
  257. bitFlag = le16toh (bitFlag);
  258. uint16_t compressionMethod;
  259. s.read ((char *)&compressionMethod, 2);
  260. compressionMethod = le16toh (compressionMethod);
  261. s.seekg (4, std::ios::cur); // skip fields we don't care about
  262. uint32_t compressedSize, uncompressedSize;
  263. uint32_t crc_32;
  264. s.read ((char *)&crc_32, 4);
  265. crc_32 = le32toh (crc_32);
  266. s.read ((char *)&compressedSize, 4);
  267. compressedSize = le32toh (compressedSize);
  268. s.read ((char *)&uncompressedSize, 4);
  269. uncompressedSize = le32toh (uncompressedSize);
  270. uint16_t fileNameLength, extraFieldLength;
  271. s.read ((char *)&fileNameLength, 2);
  272. fileNameLength = le16toh (fileNameLength);
  273. if ( fileNameLength > 255 ) {
  274. // too big
  275. LogPrint(eLogError, "Reseed: SU3 fileNameLength too large: ", fileNameLength);
  276. return numFiles;
  277. }
  278. s.read ((char *)&extraFieldLength, 2);
  279. extraFieldLength = le16toh (extraFieldLength);
  280. char localFileName[255];
  281. s.read (localFileName, fileNameLength);
  282. localFileName[fileNameLength] = 0;
  283. s.seekg (extraFieldLength, std::ios::cur);
  284. // take care about data descriptor if presented
  285. if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR)
  286. {
  287. size_t pos = s.tellg ();
  288. if (!FindZipDataDescriptor (s))
  289. {
  290. LogPrint (eLogError, "Reseed: SU3 archive data descriptor not found");
  291. return numFiles;
  292. }
  293. s.read ((char *)&crc_32, 4);
  294. crc_32 = le32toh (crc_32);
  295. s.read ((char *)&compressedSize, 4);
  296. compressedSize = le32toh (compressedSize) + 4; // ??? we must consider signature as part of compressed data
  297. s.read ((char *)&uncompressedSize, 4);
  298. uncompressedSize = le32toh (uncompressedSize);
  299. // now we know compressed and uncompressed size
  300. s.seekg (pos, std::ios::beg); // back to compressed data
  301. }
  302. LogPrint (eLogDebug, "Reseed: Processing file ", localFileName, " ", compressedSize, " bytes");
  303. if (!compressedSize)
  304. {
  305. LogPrint (eLogWarning, "Reseed: Unexpected size 0. Skipped");
  306. continue;
  307. }
  308. uint8_t * compressed = new uint8_t[compressedSize];
  309. s.read ((char *)compressed, compressedSize);
  310. if (compressionMethod) // we assume Deflate
  311. {
  312. z_stream inflator;
  313. memset (&inflator, 0, sizeof (inflator));
  314. inflateInit2 (&inflator, -MAX_WBITS); // no zlib header
  315. uint8_t * uncompressed = new uint8_t[uncompressedSize];
  316. inflator.next_in = compressed;
  317. inflator.avail_in = compressedSize;
  318. inflator.next_out = uncompressed;
  319. inflator.avail_out = uncompressedSize;
  320. int err;
  321. if ((err = inflate (&inflator, Z_SYNC_FLUSH)) >= 0)
  322. {
  323. uncompressedSize -= inflator.avail_out;
  324. if (crc32 (0, uncompressed, uncompressedSize) == crc_32)
  325. {
  326. i2p::data::netdb.AddRouterInfo (uncompressed, uncompressedSize);
  327. numFiles++;
  328. }
  329. else
  330. LogPrint (eLogError, "Reseed: CRC32 verification failed");
  331. }
  332. else
  333. LogPrint (eLogError, "Reseed: SU3 decompression error ", err);
  334. delete[] uncompressed;
  335. inflateEnd (&inflator);
  336. }
  337. else // no compression
  338. {
  339. i2p::data::netdb.AddRouterInfo (compressed, compressedSize);
  340. numFiles++;
  341. }
  342. delete[] compressed;
  343. if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR)
  344. s.seekg (12, std::ios::cur); // skip data descriptor section if presented (12 = 16 - 4)
  345. }
  346. else
  347. {
  348. if (signature != ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE)
  349. LogPrint (eLogWarning, "Reseed: Missing zip central directory header");
  350. break; // no more files
  351. }
  352. size_t end = s.tellg ();
  353. if (end - contentPos >= contentLength)
  354. break; // we are beyond contentLength
  355. }
  356. if (numFiles) // check if routers are not outdated
  357. {
  358. auto ts = i2p::util::GetMillisecondsSinceEpoch ();
  359. int numOutdated = 0;
  360. i2p::data::netdb.VisitRouterInfos (
  361. [&numOutdated, ts](std::shared_ptr<const RouterInfo> r)
  362. {
  363. if (r && ts > r->GetTimestamp () + 10*i2p::data::NETDB_MAX_EXPIRATION_TIMEOUT*1000LL) // 270 hours
  364. {
  365. LogPrint (eLogError, "Reseed: router ", r->GetIdentHash().ToBase64 (), " is outdated by ", (ts - r->GetTimestamp ())/1000LL/3600LL, " hours");
  366. numOutdated++;
  367. }
  368. });
  369. if (numOutdated > numFiles/2) // more than half
  370. {
  371. LogPrint (eLogError, "Reseed: mammoth's shit\n"
  372. " *_____*\n"
  373. " *_*****_*\n"
  374. " *_(O)_(O)_*\n"
  375. " **____V____**\n"
  376. " **_________**\n"
  377. " **_________**\n"
  378. " *_________*\n"
  379. " ***___***");
  380. i2p::data::netdb.ClearRouterInfos ();
  381. numFiles = 0;
  382. }
  383. }
  384. return numFiles;
  385. }
  386. const uint8_t ZIP_DATA_DESCRIPTOR_SIGNATURE[] = { 0x50, 0x4B, 0x07, 0x08 };
  387. bool Reseeder::FindZipDataDescriptor (std::istream& s)
  388. {
  389. size_t nextInd = 0;
  390. while (!s.eof ())
  391. {
  392. uint8_t nextByte;
  393. s.read ((char *)&nextByte, 1);
  394. if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd])
  395. {
  396. nextInd++;
  397. if (nextInd >= sizeof (ZIP_DATA_DESCRIPTOR_SIGNATURE))
  398. return true;
  399. }
  400. else
  401. nextInd = 0;
  402. }
  403. return false;
  404. }
  405. void Reseeder::LoadCertificate (const std::string& filename)
  406. {
  407. SSL_CTX * ctx = SSL_CTX_new (TLS_method ());
  408. int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
  409. if (ret)
  410. {
  411. SSL * ssl = SSL_new (ctx);
  412. X509 * cert = SSL_get_certificate (ssl);
  413. // verify
  414. if (cert)
  415. {
  416. // extract issuer name
  417. char name[100];
  418. X509_NAME_oneline (X509_get_issuer_name(cert), name, 100);
  419. char * cn = strstr (name, "CN=");
  420. if (cn)
  421. {
  422. cn += 3;
  423. char * terminator = strchr (cn, '/');
  424. if (terminator) terminator[0] = 0;
  425. }
  426. // extract RSA key (we need n only, e = 65537)
  427. RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert));
  428. const BIGNUM * n, * e, * d;
  429. RSA_get0_key(key, &n, &e, &d);
  430. PublicKey value;
  431. i2p::crypto::bn2buf (n, value, 512);
  432. if (cn)
  433. m_SigningKeys[cn] = value;
  434. else
  435. LogPrint (eLogError, "Reseed: Can't find CN field in ", filename);
  436. }
  437. SSL_free (ssl);
  438. }
  439. else
  440. LogPrint (eLogError, "Reseed: Can't open certificate file ", filename);
  441. SSL_CTX_free (ctx);
  442. }
  443. void Reseeder::LoadCertificates ()
  444. {
  445. std::string certDir = i2p::fs::DataDirPath("certificates", "reseed");
  446. std::vector<std::string> files;
  447. int numCertificates = 0;
  448. if (!i2p::fs::ReadDir(certDir, files)) {
  449. LogPrint(eLogWarning, "Reseed: Can't load reseed certificates from ", certDir);
  450. return;
  451. }
  452. for (const std::string & file : files) {
  453. if (file.compare(file.size() - 4, 4, ".crt") != 0) {
  454. LogPrint(eLogWarning, "Reseed: ignoring file ", file);
  455. continue;
  456. }
  457. LoadCertificate (file);
  458. numCertificates++;
  459. }
  460. LogPrint (eLogInfo, "Reseed: ", numCertificates, " certificates loaded");
  461. }
  462. std::string Reseeder::HttpsRequest (const std::string& address)
  463. {
  464. i2p::http::URL proxyUrl;
  465. std::string proxy; i2p::config::GetOption("reseed.proxy", proxy);
  466. // check for proxy url
  467. if(proxy.size()) {
  468. // parse
  469. if(proxyUrl.parse(proxy)) {
  470. if (proxyUrl.schema == "http" && !proxyUrl.port) {
  471. proxyUrl.port = 80;
  472. } else if (proxyUrl.schema == "socks" && !proxyUrl.port) {
  473. proxyUrl.port = 1080;
  474. }
  475. // check for valid proxy url schema
  476. if (proxyUrl.schema != "http" && proxyUrl.schema != "socks") {
  477. LogPrint(eLogError, "Reseed: bad proxy url: ", proxy);
  478. return "";
  479. }
  480. } else {
  481. LogPrint(eLogError, "Reseed: bad proxy url: ", proxy);
  482. return "";
  483. }
  484. }
  485. i2p::http::URL url;
  486. if (!url.parse(address)) {
  487. LogPrint(eLogError, "Reseed: failed to parse url: ", address);
  488. return "";
  489. }
  490. url.schema = "https";
  491. if (!url.port)
  492. url.port = 443;
  493. boost::asio::io_service service;
  494. boost::system::error_code ecode;
  495. boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
  496. ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
  497. boost::asio::ssl::stream<boost::asio::ip::tcp::socket> s(service, ctx);
  498. if(proxyUrl.schema.size())
  499. {
  500. // proxy connection
  501. auto it = boost::asio::ip::tcp::resolver(service).resolve (
  502. boost::asio::ip::tcp::resolver::query (proxyUrl.host, std::to_string(proxyUrl.port)), ecode);
  503. if(!ecode)
  504. {
  505. s.lowest_layer().connect(*it, ecode);
  506. if(!ecode)
  507. {
  508. auto & sock = s.next_layer();
  509. if(proxyUrl.schema == "http")
  510. {
  511. i2p::http::HTTPReq proxyReq;
  512. i2p::http::HTTPRes proxyRes;
  513. proxyReq.method = "CONNECT";
  514. proxyReq.version = "HTTP/1.1";
  515. proxyReq.uri = url.host + ":" + std::to_string(url.port);
  516. boost::asio::streambuf writebuf, readbuf;
  517. std::ostream out(&writebuf);
  518. out << proxyReq.to_string();
  519. boost::asio::write(sock, writebuf.data(), boost::asio::transfer_all(), ecode);
  520. if (ecode)
  521. {
  522. sock.close();
  523. LogPrint(eLogError, "Reseed: HTTP CONNECT write error: ", ecode.message());
  524. return "";
  525. }
  526. boost::asio::read_until(sock, readbuf, "\r\n\r\n", ecode);
  527. if (ecode)
  528. {
  529. sock.close();
  530. LogPrint(eLogError, "Reseed: HTTP CONNECT read error: ", ecode.message());
  531. return "";
  532. }
  533. if(proxyRes.parse(boost::asio::buffer_cast<const char *>(readbuf.data()), readbuf.size()) <= 0)
  534. {
  535. sock.close();
  536. LogPrint(eLogError, "Reseed: HTTP CONNECT malformed reply");
  537. return "";
  538. }
  539. if(proxyRes.code != 200)
  540. {
  541. sock.close();
  542. LogPrint(eLogError, "Reseed: HTTP CONNECT got bad status: ", proxyRes.code);
  543. return "";
  544. }
  545. }
  546. else
  547. {
  548. // assume socks if not http, is checked before this for other types
  549. // TODO: support username/password auth etc
  550. uint8_t hs_writebuf[3] = {0x05, 0x01, 0x00};
  551. uint8_t hs_readbuf[2];
  552. boost::asio::write(sock, boost::asio::buffer(hs_writebuf, 3), boost::asio::transfer_all(), ecode);
  553. if(ecode)
  554. {
  555. sock.close();
  556. LogPrint(eLogError, "Reseed: SOCKS handshake write failed: ", ecode.message());
  557. return "";
  558. }
  559. boost::asio::read(sock, boost::asio::buffer(hs_readbuf, 2), ecode);
  560. if(ecode)
  561. {
  562. sock.close();
  563. LogPrint(eLogError, "Reseed: SOCKS handshake read failed: ", ecode.message());
  564. return "";
  565. }
  566. size_t sz = 0;
  567. uint8_t buf[256];
  568. buf[0] = 0x05;
  569. buf[1] = 0x01;
  570. buf[2] = 0x00;
  571. buf[3] = 0x03;
  572. sz += 4;
  573. size_t hostsz = url.host.size();
  574. if(1 + 2 + hostsz + sz > sizeof(buf))
  575. {
  576. sock.close();
  577. LogPrint(eLogError, "Reseed: SOCKS handshake failed, hostname too big: ", url.host);
  578. return "";
  579. }
  580. buf[4] = (uint8_t) hostsz;
  581. memcpy(buf+5, url.host.c_str(), hostsz);
  582. sz += hostsz + 1;
  583. htobe16buf(buf+sz, url.port);
  584. sz += 2;
  585. boost::asio::write(sock, boost::asio::buffer(buf, sz), boost::asio::transfer_all(), ecode);
  586. if(ecode)
  587. {
  588. sock.close();
  589. LogPrint(eLogError, "Reseed: SOCKS handshake failed writing: ", ecode.message());
  590. return "";
  591. }
  592. boost::asio::read(sock, boost::asio::buffer(buf, 10), ecode);
  593. if(ecode)
  594. {
  595. sock.close();
  596. LogPrint(eLogError, "Reseed: SOCKS handshake failed reading: ", ecode.message());
  597. return "";
  598. }
  599. if(buf[1] != 0x00)
  600. {
  601. sock.close();
  602. LogPrint(eLogError, "Reseed: SOCKS handshake bad reply code: ", std::to_string(buf[1]));
  603. return "";
  604. }
  605. }
  606. }
  607. }
  608. }
  609. else
  610. {
  611. // direct connection
  612. auto it = boost::asio::ip::tcp::resolver(service).resolve (
  613. boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode);
  614. if(!ecode)
  615. s.lowest_layer().connect (*it, ecode);
  616. }
  617. if (!ecode)
  618. {
  619. SSL_set_tlsext_host_name(s.native_handle(), url.host.c_str ());
  620. s.handshake (boost::asio::ssl::stream_base::client, ecode);
  621. if (!ecode)
  622. {
  623. LogPrint (eLogDebug, "Reseed: Connected to ", url.host, ":", url.port);
  624. i2p::http::HTTPReq req;
  625. req.uri = url.to_string();
  626. req.AddHeader("User-Agent", "Wget/1.11.4");
  627. req.AddHeader("Connection", "close");
  628. s.write_some (boost::asio::buffer (req.to_string()));
  629. // read response
  630. std::stringstream rs;
  631. char recv_buf[1024]; size_t l = 0;
  632. do {
  633. l = s.read_some (boost::asio::buffer (recv_buf, sizeof(recv_buf)), ecode);
  634. if (l) rs.write (recv_buf, l);
  635. } while (!ecode && l);
  636. // process response
  637. std::string data = rs.str();
  638. i2p::http::HTTPRes res;
  639. int len = res.parse(data);
  640. if (len <= 0) {
  641. LogPrint(eLogWarning, "Reseed: incomplete/broken response from ", url.host);
  642. return "";
  643. }
  644. if (res.code != 200) {
  645. LogPrint(eLogError, "Reseed: failed to reseed from ", url.host, ", http code ", res.code);
  646. return "";
  647. }
  648. data.erase(0, len); /* drop http headers from response */
  649. LogPrint(eLogDebug, "Reseed: got ", data.length(), " bytes of data from ", url.host);
  650. if (res.is_chunked()) {
  651. std::stringstream in(data), out;
  652. if (!i2p::http::MergeChunkedResponse(in, out)) {
  653. LogPrint(eLogWarning, "Reseed: failed to merge chunked response from ", url.host);
  654. return "";
  655. }
  656. LogPrint(eLogDebug, "Reseed: got ", data.length(), "(", out.tellg(), ") bytes of data from ", url.host);
  657. data = out.str();
  658. }
  659. return data;
  660. }
  661. else
  662. LogPrint (eLogError, "Reseed: SSL handshake failed: ", ecode.message ());
  663. }
  664. else
  665. LogPrint (eLogError, "Reseed: Couldn't connect to ", url.host, ": ", ecode.message ());
  666. return "";
  667. }
  668. }
  669. }