diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main_gui.cpp | 4 | ||||
| -rw-r--r-- | src/net.cpp | 25 | ||||
| -rw-r--r-- | src/net.h | 1 | ||||
| -rw-r--r-- | src/nostr.cpp | 11 | ||||
| -rw-r--r-- | src/proxy.cpp | 51 |
5 files changed, 81 insertions, 11 deletions
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index deed471..f0fe903 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -143,6 +143,7 @@ static void PrintUsage() | |||
| 143 | printf(" /socks=HOST:PORT (SOCKS5 proxy for Nostr, .btf relay, and onion dials)\n"); | 143 | printf(" /socks=HOST:PORT (SOCKS5 proxy for Nostr, .btf relay, and onion dials)\n"); |
| 144 | printf(" /tor[=HOST:PORT] (Tor mode; default SOCKS5 proxy is 127.0.0.1:9050)\n"); | 144 | printf(" /tor[=HOST:PORT] (Tor mode; default SOCKS5 proxy is 127.0.0.1:9050)\n"); |
| 145 | printf(" /managedtor[=PATH] (start Tor, create a hidden service, advertise its onion)\n"); | 145 | printf(" /managedtor[=PATH] (start Tor, create a hidden service, advertise its onion)\n"); |
| 146 | printf(" /oniononly (do not fall back to rendezvous when a .btf onion dial fails)\n"); | ||
| 146 | printf(" /btfseed=ADDRESS:ENCHEX (extra bootstrap peer, repeatable)\n"); | 147 | printf(" /btfseed=ADDRESS:ENCHEX (extra bootstrap peer, repeatable)\n"); |
| 147 | printf("\n"); | 148 | printf("\n"); |
| 148 | printf("Wallet:\n"); | 149 | printf("Wallet:\n"); |
| @@ -278,6 +279,7 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 278 | string btfConnect = argval2(argc, argv, "/connectbtf", "-connectbtf"); | 279 | string btfConnect = argval2(argc, argv, "/connectbtf", "-connectbtf"); |
| 279 | if (!btfConnect.empty()) | 280 | if (!btfConnect.empty()) |
| 280 | strBtfConnect = btfConnect; | 281 | strBtfConnect = btfConnect; |
| 282 | fBtfOnionOnly = arg(argc, argv, "/oniononly") || arg(argc, argv, "-oniononly"); | ||
| 281 | 283 | ||
| 282 | string rvRelay = argval2(argc, argv, "/rvrelay", "-rvrelay"); | 284 | string rvRelay = argval2(argc, argv, "/rvrelay", "-rvrelay"); |
| 283 | if (!rvRelay.empty()) | 285 | if (!rvRelay.empty()) |
| @@ -360,6 +362,8 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 360 | BtfSocks5ProxyName().c_str()); | 362 | BtfSocks5ProxyName().c_str()); |
| 361 | } | 363 | } |
| 362 | } | 364 | } |
| 365 | if (fBtfOnionOnly && !BtfSocks5ProxyEnabled()) | ||
| 366 | fprintf(stderr, "Warning: /oniononly without /tor, /managedtor, or /socks cannot dial .onion peers\n"); | ||
| 363 | 367 | ||
| 364 | // /btfseed=ADDRESS:ENCHEX -- extra bootstrap peers, repeatable. Useful for | 368 | // /btfseed=ADDRESS:ENCHEX -- extra bootstrap peers, repeatable. Useful for |
| 365 | // testing the seed path and for private networks that ship no compiled list. | 369 | // testing the seed path and for private networks that ship no compiled list. |
diff --git a/src/net.cpp b/src/net.cpp index 6bc3c1c..997a2bd 100644 --- a/src/net.cpp +++ b/src/net.cpp | |||
| @@ -65,6 +65,8 @@ deque<pair<int64, CInv> > vRelayExpiration; | |||
| 65 | CCriticalSection cs_mapRelay; | 65 | CCriticalSection cs_mapRelay; |
| 66 | map<CInv, int64> mapAlreadyAskedFor; | 66 | map<CInv, int64> mapAlreadyAskedFor; |
| 67 | string strBtfConnect; // .btf peer to keep connected to (from /connectbtf) | 67 | string strBtfConnect; // .btf peer to keep connected to (from /connectbtf) |
| 68 | bool fBtfOnionOnly = false; // require direct onion transport for .btf peers | ||
| 69 | static const int BTF_ONION_CONNECT_TIMEOUT_SECS = 120; | ||
| 68 | 70 | ||
| 69 | int nPeersWatched = 0; | 71 | int nPeersWatched = 0; |
| 70 | int64 nBlocksReceived = 0; | 72 | int64 nBlocksReceived = 0; |
| @@ -1022,7 +1024,8 @@ static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char p | |||
| 1022 | if (SplitHostPort(strOnionNorm, strOnionHost, nOnionPort)) | 1024 | if (SplitHostPort(strOnionNorm, strOnionHost, nOnionPort)) |
| 1023 | { | 1025 | { |
| 1024 | BtfChurnNoteDialAttempt(strBtfAddr, strOnionNorm); | 1026 | BtfChurnNoteDialAttempt(strBtfAddr, strOnionNorm); |
| 1025 | SOCKET hOnionSocket = BtfConnectSocket(strOnionHost, nOnionPort, SOCK_ONION_PEER, 20); | 1027 | SOCKET hOnionSocket = BtfConnectSocket(strOnionHost, nOnionPort, SOCK_ONION_PEER, |
| 1028 | BTF_ONION_CONNECT_TIMEOUT_SECS); | ||
| 1026 | if (hOnionSocket != INVALID_SOCKET) | 1029 | if (hOnionSocket != INVALID_SOCKET) |
| 1027 | { | 1030 | { |
| 1028 | if (fDebug) | 1031 | if (fDebug) |
| @@ -1040,12 +1043,23 @@ static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char p | |||
| 1040 | return pnode; | 1043 | return pnode; |
| 1041 | } | 1044 | } |
| 1042 | if (fDebug) | 1045 | if (fDebug) |
| 1043 | LogPrint("net", "ConnectNodeBtf: direct onion to %s at %s failed, falling back to rendezvous\n", | 1046 | LogPrint("net", "ConnectNodeBtf: direct onion to %s at %s failed%s\n", |
| 1044 | strBtfAddr.c_str(), strOnionNorm.c_str()); | 1047 | strBtfAddr.c_str(), strOnionNorm.c_str(), |
| 1048 | fBtfOnionOnly ? "" : ", falling back to rendezvous"); | ||
| 1045 | BtfChurnNoteDialResult(strBtfAddr, strOnionNorm, false); | 1049 | BtfChurnNoteDialResult(strBtfAddr, strOnionNorm, false); |
| 1050 | if (fBtfOnionOnly) | ||
| 1051 | return NULL; | ||
| 1046 | } | 1052 | } |
| 1047 | } | 1053 | } |
| 1048 | 1054 | ||
| 1055 | if (fBtfOnionOnly) | ||
| 1056 | { | ||
| 1057 | if (fDebug) | ||
| 1058 | LogPrint("net", "ConnectNodeBtf: onion-only mode refused rendezvous fallback for %s\n", | ||
| 1059 | strBtfAddr.c_str()); | ||
| 1060 | return NULL; | ||
| 1061 | } | ||
| 1062 | |||
| 1049 | BtfChurnNoteDialAttempt(strBtfAddr, strMeeting); | 1063 | BtfChurnNoteDialAttempt(strBtfAddr, strMeeting); |
| 1050 | string strHost; | 1064 | string strHost; |
| 1051 | unsigned short nPort = 0; | 1065 | unsigned short nPort = 0; |
| @@ -2012,6 +2026,11 @@ bool StartNode(string& strError) | |||
| 2012 | // IP address, and port for the socket that is being bound | 2026 | // IP address, and port for the socket that is being bound |
| 2013 | int nRetryLimit = 15; | 2027 | int nRetryLimit = 15; |
| 2014 | struct sockaddr_in sockaddr = addrLocalHost.GetSockAddr(); | 2028 | struct sockaddr_in sockaddr = addrLocalHost.GetSockAddr(); |
| 2029 | // Keep addrLocalHost as this node's advertised address, but listen on all | ||
| 2030 | // local interfaces. Managed Tor forwards hidden-service traffic to | ||
| 2031 | // 127.0.0.1:<port>, and binding only to the LAN address made that onion | ||
| 2032 | // endpoint unreachable even though the P2P listener was running. | ||
| 2033 | sockaddr.sin_addr.s_addr = INADDR_ANY; | ||
| 2015 | if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) | 2034 | if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) |
| 2016 | { | 2035 | { |
| 2017 | int nErr = WSAGetLastError(); | 2036 | int nErr = WSAGetLastError(); |
| @@ -33,6 +33,7 @@ CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting | |||
| 33 | void ThreadBtfAccept(void* parg); | 33 | void ThreadBtfAccept(void* parg); |
| 34 | void ThreadBtfConnect(void* parg); | 34 | void ThreadBtfConnect(void* parg); |
| 35 | extern string strBtfConnect; | 35 | extern string strBtfConnect; |
| 36 | extern bool fBtfOnionOnly; | ||
| 36 | // Bootstrap seeds added at runtime with /btfseed=ADDRESS:ENCHEX (repeatable). | 37 | // Bootstrap seeds added at runtime with /btfseed=ADDRESS:ENCHEX (repeatable). |
| 37 | // The compiled-in list lives in net.cpp; these are appended to it. | 38 | // The compiled-in list lives in net.cpp; these are appended to it. |
| 38 | extern std::vector<std::pair<std::string, std::string> > vBtfExtraSeeds; | 39 | extern std::vector<std::pair<std::string, std::string> > vBtfExtraSeeds; |
diff --git a/src/nostr.cpp b/src/nostr.cpp index 0c1b4b6..35fde43 100644 --- a/src/nostr.cpp +++ b/src/nostr.cpp | |||
| @@ -1764,11 +1764,12 @@ void ThreadNostrSeed(void* parg) | |||
| 1764 | LogPrint("nostr", "Nostr: node pubkey = %s\n", key.PubKeyHex().c_str()); | 1764 | LogPrint("nostr", "Nostr: node pubkey = %s\n", key.PubKeyHex().c_str()); |
| 1765 | LogPrint("nostr", "Nostr: node .btf address = %s\n", key.BtfAddress().c_str()); | 1765 | LogPrint("nostr", "Nostr: node .btf address = %s\n", key.BtfAddress().c_str()); |
| 1766 | 1766 | ||
| 1767 | // The self-test below publishes a real descriptor, and PublishDescriptor now | 1767 | // The self-test below publishes a real descriptor. Rendezvous-only nodes |
| 1768 | // refuses to publish before ThreadBtfAccept has registered a rendezvous. Give | 1768 | // need ThreadBtfAccept to register first; Tor nodes can publish as soon as |
| 1769 | // registration a bounded head start so the test measures the publish/resolve | 1769 | // their signed onion endpoint exists, with rendezvous marked pending. |
| 1770 | // chain instead of losing the race against it. | 1770 | for (int i = 0; i < 60 && !fShutdown && |
| 1771 | for (int i = 0; i < 60 && !fShutdown && BtfActiveRelay().empty(); i++) | 1771 | BtfActiveRelay().empty() && |
| 1772 | BtfLocalOnionEndpoint().empty(); i++) | ||
| 1772 | Sleep(1000); | 1773 | Sleep(1000); |
| 1773 | 1774 | ||
| 1774 | // One-time self-test of the rendezvous: publish our descriptor to a relay, | 1775 | // One-time self-test of the rendezvous: publish our descriptor to a relay, |
diff --git a/src/proxy.cpp b/src/proxy.cpp index 7d30911..eed054c 100644 --- a/src/proxy.cpp +++ b/src/proxy.cpp | |||
| @@ -13,6 +13,7 @@ static bool g_fTorProxy = false; | |||
| 13 | static std::string g_socks5Host; | 13 | static std::string g_socks5Host; |
| 14 | static unsigned short g_socks5Port = 0; | 14 | static unsigned short g_socks5Port = 0; |
| 15 | static const char* DEFAULT_TOR_SOCKS5_PROXY = "127.0.0.1:9050"; | 15 | static const char* DEFAULT_TOR_SOCKS5_PROXY = "127.0.0.1:9050"; |
| 16 | static const int TOR_CONNECT_TIMEOUT_SECS = 120; | ||
| 16 | 17 | ||
| 17 | static void SetSocketTimeout(SOCKET s, int nTimeoutSecs) | 18 | static void SetSocketTimeout(SOCKET s, int nTimeoutSecs) |
| 18 | { | 19 | { |
| @@ -297,10 +298,25 @@ static bool Socks5Connect(SOCKET s, const std::string& destHost, | |||
| 297 | 298 | ||
| 298 | unsigned char hello[3] = { 0x05, 0x01, 0x00 }; // SOCKS5, one method, no auth | 299 | unsigned char hello[3] = { 0x05, 0x01, 0x00 }; // SOCKS5, one method, no auth |
| 299 | if (!WriteN(s, hello, sizeof(hello))) | 300 | if (!WriteN(s, hello, sizeof(hello))) |
| 301 | { | ||
| 302 | error("SOCKS5 hello write failed for %s:%u\n", | ||
| 303 | destHost.c_str(), (unsigned)destPort); | ||
| 300 | return false; | 304 | return false; |
| 305 | } | ||
| 301 | unsigned char choice[2] = { 0, 0 }; | 306 | unsigned char choice[2] = { 0, 0 }; |
| 302 | if (!ReadN(s, choice, sizeof(choice)) || choice[0] != 0x05 || choice[1] != 0x00) | 307 | if (!ReadN(s, choice, sizeof(choice))) |
| 308 | { | ||
| 309 | error("SOCKS5 method selection read failed for %s:%u\n", | ||
| 310 | destHost.c_str(), (unsigned)destPort); | ||
| 311 | return false; | ||
| 312 | } | ||
| 313 | if (choice[0] != 0x05 || choice[1] != 0x00) | ||
| 314 | { | ||
| 315 | error("SOCKS5 proxy rejected no-auth method for %s:%u (version=0x%02x method=0x%02x)\n", | ||
| 316 | destHost.c_str(), (unsigned)destPort, | ||
| 317 | (unsigned)choice[0], (unsigned)choice[1]); | ||
| 303 | return false; | 318 | return false; |
| 319 | } | ||
| 304 | 320 | ||
| 305 | std::vector<unsigned char> req; | 321 | std::vector<unsigned char> req; |
| 306 | req.reserve(7 + destHost.size()); | 322 | req.reserve(7 + destHost.size()); |
| @@ -313,11 +329,25 @@ static bool Socks5Connect(SOCKET s, const std::string& destHost, | |||
| 313 | req.push_back((unsigned char)(destPort >> 8)); | 329 | req.push_back((unsigned char)(destPort >> 8)); |
| 314 | req.push_back((unsigned char)(destPort & 0xff)); | 330 | req.push_back((unsigned char)(destPort & 0xff)); |
| 315 | if (!WriteN(s, &req[0], (int)req.size())) | 331 | if (!WriteN(s, &req[0], (int)req.size())) |
| 332 | { | ||
| 333 | error("SOCKS5 CONNECT request write failed for %s:%u\n", | ||
| 334 | destHost.c_str(), (unsigned)destPort); | ||
| 316 | return false; | 335 | return false; |
| 336 | } | ||
| 317 | 337 | ||
| 318 | unsigned char rep[4] = {0,0,0,0}; | 338 | unsigned char rep[4] = {0,0,0,0}; |
| 319 | if (!ReadN(s, rep, sizeof(rep)) || rep[0] != 0x05) | 339 | if (!ReadN(s, rep, sizeof(rep))) |
| 340 | { | ||
| 341 | error("SOCKS5 CONNECT reply read failed for %s:%u\n", | ||
| 342 | destHost.c_str(), (unsigned)destPort); | ||
| 320 | return false; | 343 | return false; |
| 344 | } | ||
| 345 | if (rep[0] != 0x05) | ||
| 346 | { | ||
| 347 | error("SOCKS5 CONNECT reply has invalid version 0x%02x for %s:%u\n", | ||
| 348 | (unsigned)rep[0], destHost.c_str(), (unsigned)destPort); | ||
| 349 | return false; | ||
| 350 | } | ||
| 321 | if (rep[1] != 0x00) | 351 | if (rep[1] != 0x00) |
| 322 | { | 352 | { |
| 323 | error("SOCKS5 CONNECT to %s:%u failed with reply 0x%02x\n", | 353 | error("SOCKS5 CONNECT to %s:%u failed with reply 0x%02x\n", |
| @@ -335,10 +365,20 @@ static bool Socks5Connect(SOCKET s, const std::string& destHost, | |||
| 335 | nAddr = len; | 365 | nAddr = len; |
| 336 | } | 366 | } |
| 337 | else | 367 | else |
| 368 | { | ||
| 369 | error("SOCKS5 CONNECT reply has invalid address type 0x%02x for %s:%u\n", | ||
| 370 | (unsigned)rep[3], destHost.c_str(), (unsigned)destPort); | ||
| 338 | return false; | 371 | return false; |
| 372 | } | ||
| 339 | 373 | ||
| 340 | std::vector<unsigned char> discard(nAddr + 2); | 374 | std::vector<unsigned char> discard(nAddr + 2); |
| 341 | return ReadN(s, &discard[0], (int)discard.size()); | 375 | if (!ReadN(s, &discard[0], (int)discard.size())) |
| 376 | { | ||
| 377 | error("SOCKS5 CONNECT bind address read failed for %s:%u\n", | ||
| 378 | destHost.c_str(), (unsigned)destPort); | ||
| 379 | return false; | ||
| 380 | } | ||
| 381 | return true; | ||
| 342 | } | 382 | } |
| 343 | 383 | ||
| 344 | SOCKET BtfConnectSocket(const std::string& destHost, unsigned short destPort, | 384 | SOCKET BtfConnectSocket(const std::string& destHost, unsigned short destPort, |
| @@ -347,9 +387,11 @@ SOCKET BtfConnectSocket(const std::string& destHost, unsigned short destPort, | |||
| 347 | std::string proxyHost; | 387 | std::string proxyHost; |
| 348 | unsigned short proxyPort = 0; | 388 | unsigned short proxyPort = 0; |
| 349 | bool fProxy = false; | 389 | bool fProxy = false; |
| 390 | bool fTorProxy = false; | ||
| 350 | CRITICAL_BLOCK(cs_socks5) | 391 | CRITICAL_BLOCK(cs_socks5) |
| 351 | { | 392 | { |
| 352 | fProxy = g_fSocks5Proxy; | 393 | fProxy = g_fSocks5Proxy; |
| 394 | fTorProxy = g_fTorProxy; | ||
| 353 | proxyHost = g_socks5Host; | 395 | proxyHost = g_socks5Host; |
| 354 | proxyPort = g_socks5Port; | 396 | proxyPort = g_socks5Port; |
| 355 | } | 397 | } |
| @@ -365,6 +407,9 @@ SOCKET BtfConnectSocket(const std::string& destHost, unsigned short destPort, | |||
| 365 | return ConnectDirect(destHost, destPort, nSockSite, nTimeoutSecs); | 407 | return ConnectDirect(destHost, destPort, nSockSite, nTimeoutSecs); |
| 366 | } | 408 | } |
| 367 | 409 | ||
| 410 | if (fTorProxy && nTimeoutSecs > 0 && nTimeoutSecs < TOR_CONNECT_TIMEOUT_SECS) | ||
| 411 | nTimeoutSecs = TOR_CONNECT_TIMEOUT_SECS; | ||
| 412 | |||
| 368 | SOCKET s = ConnectDirect(proxyHost, proxyPort, nSockSite, nTimeoutSecs); | 413 | SOCKET s = ConnectDirect(proxyHost, proxyPort, nSockSite, nTimeoutSecs); |
| 369 | if (s == INVALID_SOCKET) | 414 | if (s == INVALID_SOCKET) |
| 370 | return INVALID_SOCKET; | 415 | return INVALID_SOCKET; |