diff options
| author | Bitflash <admin@bitflash.network> | 2026-08-13 11:38:50 -0300 |
|---|---|---|
| committer | Bitflash <admin@bitflash.network> | 2026-08-13 11:38:50 -0300 |
| commit | c009e7cc0c5093f4c4add741cb9d131d19956871 (patch) | |
| tree | 002423e5987a3c544f469befae83519ccb29fffb /src/net.cpp | |
| parent | 851811b43be38bea48ba5d04d16987bd541dca53 (diff) | |
| parent | d2b86473a267c960a1f0c012a983176e5d962187 (diff) | |
Merge pull request 'net: add signed direct onion peer endpoints' (#32) from onion-direct-peers into main
Diffstat (limited to 'src/net.cpp')
| -rw-r--r-- | src/net.cpp | 102 |
1 files changed, 83 insertions, 19 deletions
diff --git a/src/net.cpp b/src/net.cpp index c24547e..ab17332 100644 --- a/src/net.cpp +++ b/src/net.cpp | |||
| @@ -17,6 +17,8 @@ | |||
| 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" |
| @@ -170,7 +172,7 @@ static const char* pszSockSite[SOCK_SITES] = { | |||
| 170 | "external-ip probe", "listen socket", "inbound accept", | 172 | "external-ip probe", "listen socket", "inbound accept", |
| 171 | "rendezvous dial", "rendezvous listen", "rendezvous accept", | 173 | "rendezvous dial", "rendezvous listen", "rendezvous accept", |
| 172 | "loopback pair listener", "loopback pair app end", "loopback pair pump end", | 174 | "loopback pair listener", "loopback pair app end", "loopback pair pump end", |
| 173 | "nostr relay", "stratum bridge" | 175 | "nostr relay", "direct onion peer", "stratum bridge" |
| 174 | }; | 176 | }; |
| 175 | 177 | ||
| 176 | static string SockAccountingText() | 178 | static string SockAccountingText() |
| @@ -627,6 +629,7 @@ struct CachedBtfPeer | |||
| 627 | { | 629 | { |
| 628 | string btfAddr; | 630 | string btfAddr; |
| 629 | string meeting; | 631 | string meeting; |
| 632 | string onion; | ||
| 630 | string encHex; | 633 | string encHex; |
| 631 | int64 lastSeen; | 634 | int64 lastSeen; |
| 632 | // The peer's own signed descriptor, as it announced itself. Kept verbatim | 635 | // The peer's own signed descriptor, as it announced itself. Kept verbatim |
| @@ -685,6 +688,8 @@ void LoadCachedBtfPeers(vector<CachedBtfPeer>& out) | |||
| 685 | CachedBtfPeer p; | 688 | CachedBtfPeer p; |
| 686 | p.btfAddr = o["btf"].get<string>(); | 689 | p.btfAddr = o["btf"].get<string>(); |
| 687 | p.meeting = o["meeting"].get<string>(); | 690 | p.meeting = o["meeting"].get<string>(); |
| 691 | if (o.contains("onion") && o["onion"].is_string()) | ||
| 692 | btf::NormalizeOnionEndpoint(o["onion"].get<string>(), p.onion); | ||
| 688 | p.encHex = o["enc"].get<string>(); | 693 | p.encHex = o["enc"].get<string>(); |
| 689 | p.lastSeen = o.value("seen", (int64)0); | 694 | p.lastSeen = o.value("seen", (int64)0); |
| 690 | if (o.contains("desc") && o["desc"].is_string()) | 695 | if (o.contains("desc") && o["desc"].is_string()) |
| @@ -708,7 +713,8 @@ static CCriticalSection cs_btfPeerCache; | |||
| 708 | // learned about by exchange must not cost us the ability to pass it on. | 713 | // learned about by exchange must not cost us the ability to pass it on. |
| 709 | static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting, | 714 | static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting, |
| 710 | const unsigned char enc_pub[32], | 715 | const unsigned char enc_pub[32], |
| 711 | const string& strDesc = string()) | 716 | const string& strDesc = string(), |
| 717 | const string& strOnion = string()) | ||
| 712 | { | 718 | { |
| 713 | CRITICAL_BLOCK(cs_btfPeerCache) | 719 | CRITICAL_BLOCK(cs_btfPeerCache) |
| 714 | { | 720 | { |
| @@ -716,11 +722,15 @@ static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting, | |||
| 716 | LoadCachedBtfPeers(peers); | 722 | LoadCachedBtfPeers(peers); |
| 717 | 723 | ||
| 718 | string strKeepDesc = strDesc; | 724 | string strKeepDesc = strDesc; |
| 725 | string strKeepOnion; | ||
| 726 | btf::NormalizeOnionEndpoint(strOnion, strKeepOnion); | ||
| 719 | for (size_t i = 0; i < peers.size(); i++) | 727 | for (size_t i = 0; i < peers.size(); i++) |
| 720 | if (peers[i].btfAddr == strBtfAddr) | 728 | if (peers[i].btfAddr == strBtfAddr) |
| 721 | { | 729 | { |
| 722 | if (strKeepDesc.empty()) | 730 | if (strKeepDesc.empty()) |
| 723 | strKeepDesc = peers[i].desc; | 731 | strKeepDesc = peers[i].desc; |
| 732 | if (strKeepOnion.empty()) | ||
| 733 | strKeepOnion = peers[i].onion; | ||
| 724 | peers.erase(peers.begin() + i); | 734 | peers.erase(peers.begin() + i); |
| 725 | break; | 735 | break; |
| 726 | } | 736 | } |
| @@ -728,6 +738,7 @@ static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting, | |||
| 728 | CachedBtfPeer p; | 738 | CachedBtfPeer p; |
| 729 | p.btfAddr = strBtfAddr; | 739 | p.btfAddr = strBtfAddr; |
| 730 | p.meeting = strMeeting; | 740 | p.meeting = strMeeting; |
| 741 | p.onion = strKeepOnion; | ||
| 731 | p.encHex = BytesToHex(enc_pub, 32); | 742 | p.encHex = BytesToHex(enc_pub, 32); |
| 732 | p.lastSeen = GetTime(); | 743 | p.lastSeen = GetTime(); |
| 733 | p.desc = strKeepDesc; | 744 | p.desc = strKeepDesc; |
| @@ -742,6 +753,8 @@ static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting, | |||
| 742 | nlohmann::json o; | 753 | nlohmann::json o; |
| 743 | o["btf"] = q.btfAddr; | 754 | o["btf"] = q.btfAddr; |
| 744 | o["meeting"] = q.meeting; | 755 | o["meeting"] = q.meeting; |
| 756 | if (!q.onion.empty()) | ||
| 757 | o["onion"] = q.onion; | ||
| 745 | o["enc"] = q.encHex; | 758 | o["enc"] = q.encHex; |
| 746 | o["seen"] = q.lastSeen; | 759 | o["seen"] = q.lastSeen; |
| 747 | if (!q.desc.empty()) | 760 | if (!q.desc.empty()) |
| @@ -830,7 +843,7 @@ static int TryBtfSeeds() | |||
| 830 | foreach(const string& strRelay, relays) | 843 | foreach(const string& strRelay, relays) |
| 831 | { | 844 | { |
| 832 | if (fShutdown) return nConnected; | 845 | if (fShutdown) return nConnected; |
| 833 | if (ConnectNodeBtfResolved(s.first, strRelay, enc)) | 846 | if (ConnectNodeBtfResolved(s.first, strRelay, "", enc)) |
| 834 | { | 847 | { |
| 835 | LogPrint("net", "btfseed: reached %s via %s\n", | 848 | LogPrint("net", "btfseed: reached %s via %s\n", |
| 836 | s.first.c_str(), strRelay.c_str()); | 849 | s.first.c_str(), strRelay.c_str()); |
| @@ -868,7 +881,7 @@ void ThreadReconnectCachedBtfPeers(void* parg) | |||
| 868 | if (fShutdown) return; | 881 | if (fShutdown) return; |
| 869 | unsigned char enc[32]; | 882 | unsigned char enc[32]; |
| 870 | if (!HexToBytes(p.encHex, enc, 32)) continue; | 883 | if (!HexToBytes(p.encHex, enc, 32)) continue; |
| 871 | if (ConnectNodeBtfResolved(p.btfAddr, p.meeting, enc)) | 884 | if (ConnectNodeBtfResolved(p.btfAddr, p.meeting, p.onion, enc)) |
| 872 | { | 885 | { |
| 873 | nConnected++; | 886 | nConnected++; |
| 874 | if (nConnected >= 8) break; // enough to bootstrap; the rest can wait | 887 | if (nConnected >= 8) break; // enough to bootstrap; the rest can wait |
| @@ -959,14 +972,37 @@ int BtfPexAccept(const vector<string>& vDesc) | |||
| 959 | if (!HexToBytes(d.enc, enc, 32)) | 972 | if (!HexToBytes(d.enc, enc, 32)) |
| 960 | continue; | 973 | continue; |
| 961 | 974 | ||
| 962 | RememberBtfPeer(strAddr, d.meeting_node, enc, strDesc); | 975 | RememberBtfPeer(strAddr, d.meeting_node, enc, strDesc, d.onion); |
| 963 | nKept++; | 976 | nKept++; |
| 964 | } | 977 | } |
| 965 | return nKept; | 978 | return nKept; |
| 966 | } | 979 | } |
| 967 | 980 | ||
| 981 | static bool SplitHostPort(const string& strHostPort, string& strHost, unsigned short& nPort) | ||
| 982 | { | ||
| 983 | size_t colon = strHostPort.rfind(':'); | ||
| 984 | if (colon == string::npos || colon == 0 || colon + 1 >= strHostPort.size()) | ||
| 985 | return false; | ||
| 986 | string port = strHostPort.substr(colon + 1); | ||
| 987 | for (size_t i = 0; i < port.size(); i++) | ||
| 988 | if (!isdigit((unsigned char)port[i])) | ||
| 989 | return false; | ||
| 990 | |||
| 991 | errno = 0; | ||
| 992 | char* end = NULL; | ||
| 993 | long n = strtol(port.c_str(), &end, 10); | ||
| 994 | if (errno == ERANGE || end == NULL || *end != '\0' || n <= 0 || n > 65535) | ||
| 995 | return false; | ||
| 996 | |||
| 997 | strHost = strHostPort.substr(0, colon); | ||
| 998 | nPort = (unsigned short)n; | ||
| 999 | return true; | ||
| 1000 | } | ||
| 1001 | |||
| 968 | static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char pk[32], | 1002 | static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char pk[32], |
| 969 | const string& strMeeting, const unsigned char enc_pub[32]) | 1003 | const string& strMeeting, const string& strOnion, |
| 1004 | const unsigned char enc_pub[32], | ||
| 1005 | const string& strDesc = string()) | ||
| 970 | { | 1006 | { |
| 971 | CAddress addr = BtfMarkerAddr(pk); | 1007 | CAddress addr = BtfMarkerAddr(pk); |
| 972 | CNode* pnode = FindNode(addr.ip); | 1008 | CNode* pnode = FindNode(addr.ip); |
| @@ -976,16 +1012,42 @@ static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char p | |||
| 976 | return pnode; | 1012 | return pnode; |
| 977 | } | 1013 | } |
| 978 | 1014 | ||
| 979 | BtfChurnNoteDialAttempt(strBtfAddr, strMeeting); | 1015 | string strOnionNorm; |
| 980 | size_t colon = strMeeting.rfind(':'); | 1016 | if (BtfSocks5ProxyEnabled() && btf::NormalizeOnionEndpoint(strOnion, strOnionNorm)) |
| 981 | if (colon == string::npos) | ||
| 982 | { | 1017 | { |
| 983 | BtfChurnNoteDialResult(strBtfAddr, strMeeting, false); | 1018 | string strOnionHost; |
| 984 | return NULL; | 1019 | unsigned short nOnionPort = 0; |
| 1020 | if (SplitHostPort(strOnionNorm, strOnionHost, nOnionPort)) | ||
| 1021 | { | ||
| 1022 | BtfChurnNoteDialAttempt(strBtfAddr, strOnionNorm); | ||
| 1023 | SOCKET hOnionSocket = BtfConnectSocket(strOnionHost, nOnionPort, SOCK_ONION_PEER, 20); | ||
| 1024 | if (hOnionSocket != INVALID_SOCKET) | ||
| 1025 | { | ||
| 1026 | if (fDebug) | ||
| 1027 | LogPrint("net", "connected %s via direct onion %s\n", | ||
| 1028 | strBtfAddr.c_str(), strOnionNorm.c_str()); | ||
| 1029 | BtfChurnNoteDialResult(strBtfAddr, strOnionNorm, true); | ||
| 1030 | RememberBtfPeer(strBtfAddr, strMeeting, enc_pub, strDesc, strOnionNorm); | ||
| 1031 | |||
| 1032 | pnode = new CNode(hOnionSocket, addr, false); | ||
| 1033 | pnode->strBtfAddr = strBtfAddr; | ||
| 1034 | pnode->strBtfMeeting = string("onion ") + strOnionNorm; | ||
| 1035 | pnode->AddRef(); | ||
| 1036 | CRITICAL_BLOCK(cs_vNodes) | ||
| 1037 | vNodes.push_back(pnode); | ||
| 1038 | return pnode; | ||
| 1039 | } | ||
| 1040 | if (fDebug) | ||
| 1041 | LogPrint("net", "ConnectNodeBtf: direct onion to %s at %s failed, falling back to rendezvous\n", | ||
| 1042 | strBtfAddr.c_str(), strOnionNorm.c_str()); | ||
| 1043 | BtfChurnNoteDialResult(strBtfAddr, strOnionNorm, false); | ||
| 1044 | } | ||
| 985 | } | 1045 | } |
| 986 | string strHost = strMeeting.substr(0, colon); | 1046 | |
| 987 | int nPort = atoi(strMeeting.substr(colon + 1).c_str()); | 1047 | BtfChurnNoteDialAttempt(strBtfAddr, strMeeting); |
| 988 | if (nPort <= 0 || nPort > 65535) | 1048 | string strHost; |
| 1049 | unsigned short nPort = 0; | ||
| 1050 | if (!SplitHostPort(strMeeting, strHost, nPort)) | ||
| 989 | { | 1051 | { |
| 990 | BtfChurnNoteDialResult(strBtfAddr, strMeeting, false); | 1052 | BtfChurnNoteDialResult(strBtfAddr, strMeeting, false); |
| 991 | return NULL; | 1053 | return NULL; |
| @@ -1005,7 +1067,7 @@ static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char p | |||
| 1005 | BtfChurnNoteDialResult(strBtfAddr, strMeeting, true); | 1067 | BtfChurnNoteDialResult(strBtfAddr, strMeeting, true); |
| 1006 | 1068 | ||
| 1007 | // This one answered -- worth trying first next time we start. | 1069 | // This one answered -- worth trying first next time we start. |
| 1008 | RememberBtfPeer(strBtfAddr, strMeeting, enc_pub); | 1070 | RememberBtfPeer(strBtfAddr, strMeeting, enc_pub, strDesc, strOnionNorm); |
| 1009 | 1071 | ||
| 1010 | // Add node | 1072 | // Add node |
| 1011 | pnode = new CNode(hSocket, addr, false); | 1073 | pnode = new CNode(hSocket, addr, false); |
| @@ -1035,9 +1097,10 @@ CNode* ConnectNodeBtf(const string& strBtfAddr) | |||
| 1035 | LogPrint("net", "trying %s\n", strBtfAddr.c_str()); | 1097 | LogPrint("net", "trying %s\n", strBtfAddr.c_str()); |
| 1036 | 1098 | ||
| 1037 | string strMeeting; | 1099 | string strMeeting; |
| 1100 | string strOnion; | ||
| 1038 | unsigned char enc_pub[32]; | 1101 | unsigned char enc_pub[32]; |
| 1039 | BtfChurnNoteResolveAttempt(); | 1102 | BtfChurnNoteResolveAttempt(); |
| 1040 | if (!BtfResolve(strBtfAddr, strMeeting, enc_pub)) | 1103 | if (!BtfResolve(strBtfAddr, strMeeting, enc_pub, &strOnion)) |
| 1041 | { | 1104 | { |
| 1042 | BtfChurnNoteResolveResult(false); | 1105 | BtfChurnNoteResolveResult(false); |
| 1043 | if (fDebug) | 1106 | if (fDebug) |
| @@ -1045,7 +1108,7 @@ CNode* ConnectNodeBtf(const string& strBtfAddr) | |||
| 1045 | return NULL; | 1108 | return NULL; |
| 1046 | } | 1109 | } |
| 1047 | BtfChurnNoteResolveResult(true); | 1110 | BtfChurnNoteResolveResult(true); |
| 1048 | return ConnectNodeBtfTail(strBtfAddr, pk, strMeeting, enc_pub); | 1111 | return ConnectNodeBtfTail(strBtfAddr, pk, strMeeting, strOnion, enc_pub); |
| 1049 | } | 1112 | } |
| 1050 | 1113 | ||
| 1051 | // Same as ConnectNodeBtf, but skips the Nostr resolve step because the caller | 1114 | // Same as ConnectNodeBtf, but skips the Nostr resolve step because the caller |
| @@ -1054,7 +1117,8 @@ CNode* ConnectNodeBtf(const string& strBtfAddr) | |||
| 1054 | // address). Makes zero relay connections -- only talks to the peer's | 1117 | // address). Makes zero relay connections -- only talks to the peer's |
| 1055 | // rendezvous meeting node. | 1118 | // rendezvous meeting node. |
| 1056 | CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting, | 1119 | CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting, |
| 1057 | const unsigned char enc_pub[32]) | 1120 | const string& strOnion, const unsigned char enc_pub[32], |
| 1121 | const string& strDesc) | ||
| 1058 | { | 1122 | { |
| 1059 | unsigned char pk[32]; | 1123 | unsigned char pk[32]; |
| 1060 | if (!btf::ParseAddress(strBtfAddr, pk)) | 1124 | if (!btf::ParseAddress(strBtfAddr, pk)) |
| @@ -1064,7 +1128,7 @@ CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting | |||
| 1064 | } | 1128 | } |
| 1065 | if (BtfLocalAddress() == strBtfAddr) | 1129 | if (BtfLocalAddress() == strBtfAddr) |
| 1066 | return NULL; // ourselves | 1130 | return NULL; // ourselves |
| 1067 | return ConnectNodeBtfTail(strBtfAddr, pk, strMeeting, enc_pub); | 1131 | return ConnectNodeBtfTail(strBtfAddr, pk, strMeeting, strOnion, enc_pub, strDesc); |
| 1068 | } | 1132 | } |
| 1069 | 1133 | ||
| 1070 | // Anonymous inbound listener (this node's `.btf` hidden service). Registers at | 1134 | // Anonymous inbound listener (this node's `.btf` hidden service). Registers at |