From 0b8b693d7d9cc5a94fe8e0f0adac26ed481cdf8c Mon Sep 17 00:00:00 2001 From: Sami Ahmed Date: Sat, 4 Apr 2026 03:10:43 -0700 Subject: [PATCH] Upgrade seed fetch to HTTPS + add hardcoded onion seeds The seeds.cryptographic-triangles.org endpoint uses Caddy with auto-TLS, so the daemon's seed fetcher now connects over HTTPS (port 443) using OpenSSL instead of plain HTTP (port 80) which got a 308 redirect. Also hardcodes 5 known onion seed addresses in onionseed.h as a fallback for initial peer discovery when the HTTPS endpoint is unreachable. Co-Authored-By: Claude Opus 4.6 --- src/net.cpp | 95 +++++++++++++++++++++++++++++++++++++++---------- src/onionseed.h | 10 ++++-- 2 files changed, 84 insertions(+), 21 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 9816047..632cb25 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -13,6 +13,9 @@ #include "ui_interface.h" #include "onionseed.h" +#include +#include + #include #ifdef WIN32 @@ -1433,7 +1436,7 @@ void ThreadHTTPSeedFetch2(void* parg) { static const char* DEFAULT_SEED_URL_HOST = "seeds.cryptographic-triangles.org"; static const char* DEFAULT_SEED_URL_PATH = "/seeds.txt"; - static const int HTTP_PORT = 80; + static const int HTTPS_PORT = 443; std::string seedHost = GetArg("-seedurl", DEFAULT_SEED_URL_HOST); std::string seedPath = DEFAULT_SEED_URL_PATH; @@ -1445,20 +1448,62 @@ void ThreadHTTPSeedFetch2(void* parg) seedHost = seedHost.substr(0, slashPos); } - printf("Fetching seed list from http://%s%s (via Tor)...\n", seedHost.c_str(), seedPath.c_str()); + printf("Fetching seed list from https://%s%s (via Tor)...\n", seedHost.c_str(), seedPath.c_str()); + + SSL_CTX* ctx = NULL; + SSL* ssl = NULL; + SOCKET hSocket = INVALID_SOCKET; try { // Connect through Tor SOCKS proxy using existing proxy-aware socket infrastructure - SOCKET hSocket = INVALID_SOCKET; CService addrResolved; - std::string connectDest = seedHost + ":" + std::to_string(HTTP_PORT); + std::string connectDest = seedHost + ":" + std::to_string(HTTPS_PORT); - if (!ConnectSocketByName(addrResolved, hSocket, connectDest.c_str(), HTTP_PORT, nConnectTimeout)) { - printf("HTTP seed fetch: cannot connect to %s through Tor proxy\n", seedHost.c_str()); + if (!ConnectSocketByName(addrResolved, hSocket, connectDest.c_str(), HTTPS_PORT, nConnectTimeout)) { + printf("HTTPS seed fetch: cannot connect to %s through Tor proxy\n", seedHost.c_str()); return; } - // Send HTTP request + // Set up TLS over the connected socket + ctx = SSL_CTX_new(TLS_client_method()); + if (!ctx) { + printf("HTTPS seed fetch: SSL_CTX_new failed\n"); + closesocket(hSocket); + return; + } + + // Use system default CA certificates for verification + SSL_CTX_set_default_verify_paths(ctx); + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + + ssl = SSL_new(ctx); + if (!ssl) { + printf("HTTPS seed fetch: SSL_new failed\n"); + SSL_CTX_free(ctx); + closesocket(hSocket); + return; + } + + // Set SNI hostname (required for Caddy/Let's Encrypt) + SSL_set_tlsext_host_name(ssl, seedHost.c_str()); + SSL_set_fd(ssl, (int)hSocket); + + int ret = SSL_connect(ssl); + if (ret != 1) { + int sslErr = SSL_get_error(ssl, ret); + unsigned long errCode = ERR_get_error(); + char errBuf[256]; + ERR_error_string_n(errCode, errBuf, sizeof(errBuf)); + printf("HTTPS seed fetch: TLS handshake failed (ssl_err=%d): %s\n", sslErr, errBuf); + SSL_free(ssl); + SSL_CTX_free(ctx); + closesocket(hSocket); + return; + } + + printf("HTTPS seed fetch: TLS connection established to %s\n", seedHost.c_str()); + + // Send HTTP request over TLS std::string request = "GET " + seedPath + " HTTP/1.1\r\n" "Host: " + seedHost + "\r\n" @@ -1469,41 +1514,52 @@ void ThreadHTTPSeedFetch2(void* parg) int nSent = 0; int nLen = request.size(); while (nSent < nLen) { - int nBytes = send(hSocket, request.c_str() + nSent, nLen - nSent, 0); + int nBytes = SSL_write(ssl, request.c_str() + nSent, nLen - nSent); if (nBytes <= 0) { - printf("HTTP seed fetch: send failed\n"); + printf("HTTPS seed fetch: SSL_write failed\n"); + SSL_shutdown(ssl); + SSL_free(ssl); + SSL_CTX_free(ctx); closesocket(hSocket); return; } nSent += nBytes; } - // Read response + // Read response over TLS std::string response; char buf[4096]; while (true) { - int nBytes = recv(hSocket, buf, sizeof(buf), 0); + int nBytes = SSL_read(ssl, buf, sizeof(buf)); if (nBytes <= 0) break; response.append(buf, nBytes); } + + SSL_shutdown(ssl); + SSL_free(ssl); + SSL_CTX_free(ctx); closesocket(hSocket); + ssl = NULL; + ctx = NULL; + hSocket = INVALID_SOCKET; if (response.empty()) { - printf("HTTP seed fetch: empty response from %s\n", seedHost.c_str()); + printf("HTTPS seed fetch: empty response from %s\n", seedHost.c_str()); return; } // Parse HTTP response - find end of headers size_t headerEnd = response.find("\r\n\r\n"); if (headerEnd == std::string::npos) { - printf("HTTP seed fetch: malformed response (no header terminator)\n"); + printf("HTTPS seed fetch: malformed response (no header terminator)\n"); return; } // Check status code - if (response.substr(0, 12).find("200") == std::string::npos) { - printf("HTTP seed fetch: non-200 response from %s\n", seedHost.c_str()); + std::string statusLine = response.substr(0, response.find("\r\n")); + if (statusLine.find("200") == std::string::npos) { + printf("HTTPS seed fetch: %s from %s\n", statusLine.c_str(), seedHost.c_str()); return; } @@ -1560,15 +1616,18 @@ void ThreadHTTPSeedFetch2(void* parg) if (resolved) { CAddress addr(CService(parsed, port)); addr.nTime = GetTime() - 3*24*60*60; // 3 days ago - addrman.Add(addr, CNetAddr("http-seed", true)); + addrman.Add(addr, CNetAddr("https-seed", true)); found++; } } - printf("%d addresses found from HTTP seed list (%s)\n", found, seedHost.c_str()); + printf("%d addresses found from HTTPS seed list (%s)\n", found, seedHost.c_str()); } catch (std::exception& e) { - printf("HTTP seed fetch failed: %s\n", e.what()); + printf("HTTPS seed fetch failed: %s\n", e.what()); + if (ssl) { SSL_shutdown(ssl); SSL_free(ssl); } + if (ctx) SSL_CTX_free(ctx); + if (hSocket != INVALID_SOCKET) closesocket(hSocket); } } diff --git a/src/onionseed.h b/src/onionseed.h index e79ec88..eabb587 100644 --- a/src/onionseed.h +++ b/src/onionseed.h @@ -2,10 +2,14 @@ #ifndef TRIANGLES_ONIONSEED_H #define TRIANGLES_ONIONSEED_H -// Onion seeds are now fetched dynamically via HTTP seed list. -// No hardcoded onion addresses - they go stale when Tor services restart. -// See: seeds.cryptographic-triangles.org +// Hardcoded onion seed nodes for initial peer discovery. +// Also fetched dynamically via https://seeds.cryptographic-triangles.org/seeds.txt static const char *strMainNetOnionSeed[][1] = { + {"jbpfhe7zw3qm67wy3j2ayysp3mnrjobopthnko3b3sgahqtecblwqmid.onion"}, + {"uddaxjbo3lh2zskg7w6gwln4ty5cel7q4c5jbx7fdtv6zf2j47gdlyad.onion"}, + {"el5sirhhleecuctpeeprelzubpqmoqivvra3rzlwbjttinxa4fq3wnid.onion"}, + {"sj5dhybnlp3v4y5niyc5unrnd6s43lyx5ibup7rolyosjbi2u2hsbvyd.onion"}, + {"i3kr5meha7se4ns3wss3h7v46m6uksfzv4wrohdqxpj6n35wyo2bvlid.onion"}, {NULL} };