upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-08-26 22:41:53 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-08-26 22:41:53 +0000
commitbbe04dc8c96b4c4766d2771d3438233bf82687c0 (patch)
tree62e5a1febfb8e9bc38d133ac7981e9ef93918484 /src/net.cpp
parent991853fa55a749d28d6f9e507ce72b289df92785 (diff)
parent9e39a50d1f110020b0841d31e4b931aa877cc448 (diff)
Merge upstream v1.2.19 into the fork
Merges upstream tag v1.2.19 (9e39a50) into merge/upstream-1.2.18 (991853f). Unlike the 1.2.15->1.2.18 replay, bc3de30 is a true ancestor of our branch via a9b4f89, so this is an ordinary three-way merge with merge-base bc3de30. Delta: 36 files, +3265/-163, the Tor onion transport (managed Tor, signed direct onion endpoints, onion-only dial mode) and the nHDNext restore fix. src/main.cpp, main.h, script.cpp/h and db.cpp/h are byte-identical between the two tags, and the poll() socket loop carries no diff hunks, so the merge is consensus-neutral and the soak-tested socket paths are unchanged. relay/ is untouched; the payout ledger (rpc.cpp) is untouched. 7 conflict blocks in 6 files, resolved as follows. Makefile -- VERSION. Ours: stays 1.2.19+sec with the naming comment updated, so artifacts from this tree cannot be mistaken for the upstream release. src/Makefile, src/makefile.mingw -- HEADERS list. Ours (no market.h) plus their tor.h. NODE_OBJS auto-merged correctly: no market.o, tor.o present. src/selftest.cpp -- known-tests list. Union: payout-ledger (ours) and managed-tor (theirs). src/main_gui.cpp -- one block. Our /dumpaddresses kept; their BtfStopManagedTor() on the StartNode failure path taken. The /rvrelay pin, /noannounce and the marketplace removal auto-merged and were verified intact. src/nostr.cpp -- two blocks in ResolveDescriptor. Signature takes both out-params (our fExchangeOk, their rawOut). The body keeps our drain-to-EOSE read -- returning early poisons the pooled socket for the next caller -- and adds their rawOut capture. Our TLS 1.2 floor (SSL_CTX_set_min_proto_version) is untouched by this merge; upstream 1.2.19 still has no floor of its own. Upstream's release commit also added four build logs and a compiled Python cache (build-1219.log, build-17.log, build-appimage.log, build-node.log, scripts/__pycache__/bitflash_chain.cpython-313.pyc). Removed here; they are build output, not source.
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp145
1 files changed, 126 insertions, 19 deletions
diff --git a/src/net.cpp b/src/net.cpp
index bb39122..35baf21 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -17,9 +17,12 @@
17#include <poll.h> 17#include <poll.h>
18#endif 18#endif
19#include <openssl/rand.h> 19#include <openssl/rand.h>
20#include <cerrno>
21#include <cstdlib>
20#include "btfaddr.h" 22#include "btfaddr.h"
21#include "btftunnel.h" 23#include "btftunnel.h"
22#include "proxy.h" 24#include "proxy.h"
25#include "tor.h"
23 26
24void ThreadReconnectCachedBtfPeers(void* parg); 27void ThreadReconnectCachedBtfPeers(void* parg);
25void ThreadMessageHandler2(void* parg); 28void ThreadMessageHandler2(void* parg);
@@ -62,6 +65,8 @@ deque<pair<int64, CInv> > vRelayExpiration;
62CCriticalSection cs_mapRelay; 65CCriticalSection cs_mapRelay;
63map<CInv, int64> mapAlreadyAskedFor; 66map<CInv, int64> mapAlreadyAskedFor;
64string strBtfConnect; // .btf peer to keep connected to (from /connectbtf) 67string strBtfConnect; // .btf peer to keep connected to (from /connectbtf)
68bool fBtfOnionOnly = false; // require direct onion transport for .btf peers
69static const int BTF_ONION_CONNECT_TIMEOUT_SECS = 120;
65 70
66int nPeersWatched = 0; 71int nPeersWatched = 0;
67int64 nBlocksReceived = 0; 72int64 nBlocksReceived = 0;
@@ -170,7 +175,7 @@ static const char* pszSockSite[SOCK_SITES] = {
170 "external-ip probe", "listen socket", "inbound accept", 175 "external-ip probe", "listen socket", "inbound accept",
171 "rendezvous dial", "rendezvous listen", "rendezvous accept", 176 "rendezvous dial", "rendezvous listen", "rendezvous accept",
172 "loopback pair listener", "loopback pair app end", "loopback pair pump end", 177 "loopback pair listener", "loopback pair app end", "loopback pair pump end",
173 "nostr relay", "stratum bridge" 178 "nostr relay", "direct onion peer", "stratum bridge"
174}; 179};
175 180
176static string SockAccountingText() 181static string SockAccountingText()
@@ -263,15 +268,21 @@ string GetDiagnosticsText()
263 int64 nNow = GetTime(); 268 int64 nNow = GetTime();
264 string str; 269 string str;
265 270
266 int nInbound = 0, nHeld = 0; 271 int nInbound = 0, nHeld = 0, nDirectOnion = 0, nRendezvous = 0;
267 vector<CNode*> vCopy; 272 vector<CNode*> vCopy;
268 CRITICAL_BLOCK(cs_vNodes) 273 CRITICAL_BLOCK(cs_vNodes)
269 { 274 {
270 vCopy = vNodes; 275 vCopy = vNodes;
271 nHeld = (int)vNodes.size(); 276 nHeld = (int)vNodes.size();
272 foreach(CNode* pnode, vNodes) 277 foreach(CNode* pnode, vNodes)
278 {
273 if (pnode->fInbound) 279 if (pnode->fInbound)
274 nInbound++; 280 nInbound++;
281 if (pnode->strBtfMeeting.find(".onion:") != string::npos)
282 nDirectOnion++;
283 else if (!pnode->strBtfMeeting.empty())
284 nRendezvous++;
285 }
275 } 286 }
276 287
277 int nMedian = GetPeerMedianHeight(); 288 int nMedian = GetPeerMedianHeight();
@@ -294,6 +305,23 @@ string GetDiagnosticsText()
294 str += strprintf(" peers watched %d of %d held by poll%s\n", 305 str += strprintf(" peers watched %d of %d held by poll%s\n",
295 nPeersWatched, nHeld, 306 nPeersWatched, nHeld,
296 nHeld > nPeersWatched ? " <-- NOT ALL PEERS ARE BEING READ" : ""); 307 nHeld > nPeersWatched ? " <-- NOT ALL PEERS ARE BEING READ" : "");
308 str += strprintf(" managed Tor %s\n", BtfManagedTorStatus().c_str());
309
310 string strTorMode = "disabled";
311 if (BtfManagedTorEnabled())
312 strTorMode = "managed";
313 else if (BtfTorProxyEnabled())
314 strTorMode = "external";
315 else if (BtfSocks5ProxyEnabled())
316 strTorMode = "socks5";
317 string strOnion = BtfLocalOnionEndpoint();
318 str += strprintf(" Tor mode %s%s\n",
319 strTorMode.c_str(),
320 fBtfOnionOnly ? " (onion-only)" : "");
321 str += strprintf(" onion endpoint %s\n",
322 strOnion.empty() ? "none" : strOnion.c_str());
323 str += strprintf(" .btf peers %d direct onion, %d rendezvous\n",
324 nDirectOnion, nRendezvous);
297 325
298 if (nBlocksReceived > 0) 326 if (nBlocksReceived > 0)
299 str += strprintf(" blocks received %lld (%lld arrived without a parent, %.1f%%)\n", 327 str += strprintf(" blocks received %lld (%lld arrived without a parent, %.1f%%)\n",
@@ -544,6 +572,7 @@ struct CachedBtfPeer
544{ 572{
545 string btfAddr; 573 string btfAddr;
546 string meeting; 574 string meeting;
575 string onion;
547 string encHex; 576 string encHex;
548 int64 lastSeen; 577 int64 lastSeen;
549 // The peer's own signed descriptor, as it announced itself. Kept verbatim 578 // The peer's own signed descriptor, as it announced itself. Kept verbatim
@@ -602,6 +631,8 @@ void LoadCachedBtfPeers(vector<CachedBtfPeer>& out)
602 CachedBtfPeer p; 631 CachedBtfPeer p;
603 p.btfAddr = o["btf"].get<string>(); 632 p.btfAddr = o["btf"].get<string>();
604 p.meeting = o["meeting"].get<string>(); 633 p.meeting = o["meeting"].get<string>();
634 if (o.contains("onion") && o["onion"].is_string())
635 btf::NormalizeOnionEndpoint(o["onion"].get<string>(), p.onion);
605 p.encHex = o["enc"].get<string>(); 636 p.encHex = o["enc"].get<string>();
606 p.lastSeen = o.value("seen", (int64)0); 637 p.lastSeen = o.value("seen", (int64)0);
607 if (o.contains("desc") && o["desc"].is_string()) 638 if (o.contains("desc") && o["desc"].is_string())
@@ -625,7 +656,8 @@ static CCriticalSection cs_btfPeerCache;
625// learned about by exchange must not cost us the ability to pass it on. 656// learned about by exchange must not cost us the ability to pass it on.
626static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting, 657static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting,
627 const unsigned char enc_pub[32], 658 const unsigned char enc_pub[32],
628 const string& strDesc = string()) 659 const string& strDesc = string(),
660 const string& strOnion = string())
629{ 661{
630 CRITICAL_BLOCK(cs_btfPeerCache) 662 CRITICAL_BLOCK(cs_btfPeerCache)
631 { 663 {
@@ -633,11 +665,15 @@ static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting,
633 LoadCachedBtfPeers(peers); 665 LoadCachedBtfPeers(peers);
634 666
635 string strKeepDesc = strDesc; 667 string strKeepDesc = strDesc;
668 string strKeepOnion;
669 btf::NormalizeOnionEndpoint(strOnion, strKeepOnion);
636 for (size_t i = 0; i < peers.size(); i++) 670 for (size_t i = 0; i < peers.size(); i++)
637 if (peers[i].btfAddr == strBtfAddr) 671 if (peers[i].btfAddr == strBtfAddr)
638 { 672 {
639 if (strKeepDesc.empty()) 673 if (strKeepDesc.empty())
640 strKeepDesc = peers[i].desc; 674 strKeepDesc = peers[i].desc;
675 if (strKeepOnion.empty())
676 strKeepOnion = peers[i].onion;
641 peers.erase(peers.begin() + i); 677 peers.erase(peers.begin() + i);
642 break; 678 break;
643 } 679 }
@@ -645,6 +681,7 @@ static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting,
645 CachedBtfPeer p; 681 CachedBtfPeer p;
646 p.btfAddr = strBtfAddr; 682 p.btfAddr = strBtfAddr;
647 p.meeting = strMeeting; 683 p.meeting = strMeeting;
684 p.onion = strKeepOnion;
648 p.encHex = BytesToHex(enc_pub, 32); 685 p.encHex = BytesToHex(enc_pub, 32);
649 p.lastSeen = GetTime(); 686 p.lastSeen = GetTime();
650 p.desc = strKeepDesc; 687 p.desc = strKeepDesc;
@@ -659,6 +696,8 @@ static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting,
659 nlohmann::json o; 696 nlohmann::json o;
660 o["btf"] = q.btfAddr; 697 o["btf"] = q.btfAddr;
661 o["meeting"] = q.meeting; 698 o["meeting"] = q.meeting;
699 if (!q.onion.empty())
700 o["onion"] = q.onion;
662 o["enc"] = q.encHex; 701 o["enc"] = q.encHex;
663 o["seen"] = q.lastSeen; 702 o["seen"] = q.lastSeen;
664 if (!q.desc.empty()) 703 if (!q.desc.empty())
@@ -747,7 +786,7 @@ static int TryBtfSeeds()
747 foreach(const string& strRelay, relays) 786 foreach(const string& strRelay, relays)
748 { 787 {
749 if (fShutdown) return nConnected; 788 if (fShutdown) return nConnected;
750 if (ConnectNodeBtfResolved(s.first, strRelay, enc)) 789 if (ConnectNodeBtfResolved(s.first, strRelay, "", enc))
751 { 790 {
752 LogPrint("net", "btfseed: reached %s via %s\n", 791 LogPrint("net", "btfseed: reached %s via %s\n",
753 s.first.c_str(), strRelay.c_str()); 792 s.first.c_str(), strRelay.c_str());
@@ -785,7 +824,7 @@ void ThreadReconnectCachedBtfPeers(void* parg)
785 if (fShutdown) return; 824 if (fShutdown) return;
786 unsigned char enc[32]; 825 unsigned char enc[32];
787 if (!HexToBytes(p.encHex, enc, 32)) continue; 826 if (!HexToBytes(p.encHex, enc, 32)) continue;
788 if (ConnectNodeBtfResolved(p.btfAddr, p.meeting, enc)) 827 if (ConnectNodeBtfResolved(p.btfAddr, p.meeting, p.onion, enc))
789 { 828 {
790 nConnected++; 829 nConnected++;
791 if (nConnected >= 8) break; // enough to bootstrap; the rest can wait 830 if (nConnected >= 8) break; // enough to bootstrap; the rest can wait
@@ -876,14 +915,37 @@ int BtfPexAccept(const vector<string>& vDesc)
876 if (!HexToBytes(d.enc, enc, 32)) 915 if (!HexToBytes(d.enc, enc, 32))
877 continue; 916 continue;
878 917
879 RememberBtfPeer(strAddr, d.meeting_node, enc, strDesc); 918 RememberBtfPeer(strAddr, d.meeting_node, enc, strDesc, d.onion);
880 nKept++; 919 nKept++;
881 } 920 }
882 return nKept; 921 return nKept;
883} 922}
884 923
924static bool SplitHostPort(const string& strHostPort, string& strHost, unsigned short& nPort)
925{
926 size_t colon = strHostPort.rfind(':');
927 if (colon == string::npos || colon == 0 || colon + 1 >= strHostPort.size())
928 return false;
929 string port = strHostPort.substr(colon + 1);
930 for (size_t i = 0; i < port.size(); i++)
931 if (!isdigit((unsigned char)port[i]))
932 return false;
933
934 errno = 0;
935 char* end = NULL;
936 long n = strtol(port.c_str(), &end, 10);
937 if (errno == ERANGE || end == NULL || *end != '\0' || n <= 0 || n > 65535)
938 return false;
939
940 strHost = strHostPort.substr(0, colon);
941 nPort = (unsigned short)n;
942 return true;
943}
944
885static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char pk[32], 945static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char pk[32],
886 const string& strMeeting, const unsigned char enc_pub[32]) 946 const string& strMeeting, const string& strOnion,
947 const unsigned char enc_pub[32],
948 const string& strDesc = string())
887{ 949{
888 CAddress addr = BtfMarkerAddr(pk); 950 CAddress addr = BtfMarkerAddr(pk);
889 CNode* pnode = FindNode(addr.ip); 951 CNode* pnode = FindNode(addr.ip);
@@ -893,16 +955,54 @@ static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char p
893 return pnode; 955 return pnode;
894 } 956 }
895 957
896 BtfChurnNoteDialAttempt(strBtfAddr, strMeeting); 958 string strOnionNorm;
897 size_t colon = strMeeting.rfind(':'); 959 if (BtfSocks5ProxyEnabled() && btf::NormalizeOnionEndpoint(strOnion, strOnionNorm))
898 if (colon == string::npos)
899 { 960 {
900 BtfChurnNoteDialResult(strBtfAddr, strMeeting, false); 961 string strOnionHost;
962 unsigned short nOnionPort = 0;
963 if (SplitHostPort(strOnionNorm, strOnionHost, nOnionPort))
964 {
965 BtfChurnNoteDialAttempt(strBtfAddr, strOnionNorm);
966 SOCKET hOnionSocket = BtfConnectSocket(strOnionHost, nOnionPort, SOCK_ONION_PEER,
967 BTF_ONION_CONNECT_TIMEOUT_SECS);
968 if (hOnionSocket != INVALID_SOCKET)
969 {
970 if (fDebug)
971 LogPrint("net", "connected %s via direct onion %s\n",
972 strBtfAddr.c_str(), strOnionNorm.c_str());
973 BtfChurnNoteDialResult(strBtfAddr, strOnionNorm, true);
974 RememberBtfPeer(strBtfAddr, strMeeting, enc_pub, strDesc, strOnionNorm);
975
976 pnode = new CNode(hOnionSocket, addr, false);
977 pnode->strBtfAddr = strBtfAddr;
978 pnode->strBtfMeeting = string("onion ") + strOnionNorm;
979 pnode->AddRef();
980 CRITICAL_BLOCK(cs_vNodes)
981 vNodes.push_back(pnode);
982 return pnode;
983 }
984 if (fDebug)
985 LogPrint("net", "ConnectNodeBtf: direct onion to %s at %s failed%s\n",
986 strBtfAddr.c_str(), strOnionNorm.c_str(),
987 fBtfOnionOnly ? "" : ", falling back to rendezvous");
988 BtfChurnNoteDialResult(strBtfAddr, strOnionNorm, false);
989 if (fBtfOnionOnly)
990 return NULL;
991 }
992 }
993
994 if (fBtfOnionOnly)
995 {
996 if (fDebug)
997 LogPrint("net", "ConnectNodeBtf: onion-only mode refused rendezvous fallback for %s\n",
998 strBtfAddr.c_str());
901 return NULL; 999 return NULL;
902 } 1000 }
903 string strHost = strMeeting.substr(0, colon); 1001
904 int nPort = atoi(strMeeting.substr(colon + 1).c_str()); 1002 BtfChurnNoteDialAttempt(strBtfAddr, strMeeting);
905 if (nPort <= 0 || nPort > 65535) 1003 string strHost;
1004 unsigned short nPort = 0;
1005 if (!SplitHostPort(strMeeting, strHost, nPort))
906 { 1006 {
907 BtfChurnNoteDialResult(strBtfAddr, strMeeting, false); 1007 BtfChurnNoteDialResult(strBtfAddr, strMeeting, false);
908 return NULL; 1008 return NULL;
@@ -922,7 +1022,7 @@ static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char p
922 BtfChurnNoteDialResult(strBtfAddr, strMeeting, true); 1022 BtfChurnNoteDialResult(strBtfAddr, strMeeting, true);
923 1023
924 // This one answered -- worth trying first next time we start. 1024 // This one answered -- worth trying first next time we start.
925 RememberBtfPeer(strBtfAddr, strMeeting, enc_pub); 1025 RememberBtfPeer(strBtfAddr, strMeeting, enc_pub, strDesc, strOnionNorm);
926 1026
927 // Add node 1027 // Add node
928 pnode = new CNode(hSocket, addr, false); 1028 pnode = new CNode(hSocket, addr, false);
@@ -952,9 +1052,10 @@ CNode* ConnectNodeBtf(const string& strBtfAddr)
952 LogPrint("net", "trying %s\n", strBtfAddr.c_str()); 1052 LogPrint("net", "trying %s\n", strBtfAddr.c_str());
953 1053
954 string strMeeting; 1054 string strMeeting;
1055 string strOnion;
955 unsigned char enc_pub[32]; 1056 unsigned char enc_pub[32];
956 BtfChurnNoteResolveAttempt(); 1057 BtfChurnNoteResolveAttempt();
957 if (!BtfResolve(strBtfAddr, strMeeting, enc_pub)) 1058 if (!BtfResolve(strBtfAddr, strMeeting, enc_pub, &strOnion))
958 { 1059 {
959 BtfChurnNoteResolveResult(false); 1060 BtfChurnNoteResolveResult(false);
960 if (fDebug) 1061 if (fDebug)
@@ -962,7 +1063,7 @@ CNode* ConnectNodeBtf(const string& strBtfAddr)
962 return NULL; 1063 return NULL;
963 } 1064 }
964 BtfChurnNoteResolveResult(true); 1065 BtfChurnNoteResolveResult(true);
965 return ConnectNodeBtfTail(strBtfAddr, pk, strMeeting, enc_pub); 1066 return ConnectNodeBtfTail(strBtfAddr, pk, strMeeting, strOnion, enc_pub);
966} 1067}
967 1068
968// Same as ConnectNodeBtf, but skips the Nostr resolve step because the caller 1069// Same as ConnectNodeBtf, but skips the Nostr resolve step because the caller
@@ -971,7 +1072,8 @@ CNode* ConnectNodeBtf(const string& strBtfAddr)
971// address). Makes zero relay connections -- only talks to the peer's 1072// address). Makes zero relay connections -- only talks to the peer's
972// rendezvous meeting node. 1073// rendezvous meeting node.
973CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting, 1074CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting,
974 const unsigned char enc_pub[32]) 1075 const string& strOnion, const unsigned char enc_pub[32],
1076 const string& strDesc)
975{ 1077{
976 unsigned char pk[32]; 1078 unsigned char pk[32];
977 if (!btf::ParseAddress(strBtfAddr, pk)) 1079 if (!btf::ParseAddress(strBtfAddr, pk))
@@ -981,7 +1083,7 @@ CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting
981 } 1083 }
982 if (BtfLocalAddress() == strBtfAddr) 1084 if (BtfLocalAddress() == strBtfAddr)
983 return NULL; // ourselves 1085 return NULL; // ourselves
984 return ConnectNodeBtfTail(strBtfAddr, pk, strMeeting, enc_pub); 1086 return ConnectNodeBtfTail(strBtfAddr, pk, strMeeting, strOnion, enc_pub, strDesc);
985} 1087}
986 1088
987// Anonymous inbound listener (this node's `.btf` hidden service). Registers at 1089// Anonymous inbound listener (this node's `.btf` hidden service). Registers at
@@ -1936,6 +2038,11 @@ bool StartNode(string& strError)
1936 // IP address, and port for the socket that is being bound 2038 // IP address, and port for the socket that is being bound
1937 int nRetryLimit = 15; 2039 int nRetryLimit = 15;
1938 struct sockaddr_in sockaddr = addrLocalHost.GetSockAddr(); 2040 struct sockaddr_in sockaddr = addrLocalHost.GetSockAddr();
2041 // Keep addrLocalHost as this node's advertised address, but listen on all
2042 // local interfaces. Managed Tor forwards hidden-service traffic to
2043 // 127.0.0.1:<port>, and binding only to the LAN address made that onion
2044 // endpoint unreachable even though the P2P listener was running.
2045 sockaddr.sin_addr.s_addr = INADDR_ANY;
1939 if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) 2046 if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
1940 { 2047 {
1941 int nErr = WSAGetLastError(); 2048 int nErr = WSAGetLastError();