diff options
Diffstat (limited to 'src/net.cpp')
| -rw-r--r-- | src/net.cpp | 145 |
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 | ||
| 24 | void ThreadReconnectCachedBtfPeers(void* parg); | 27 | void ThreadReconnectCachedBtfPeers(void* parg); |
| 25 | void ThreadMessageHandler2(void* parg); | 28 | void ThreadMessageHandler2(void* parg); |
| @@ -62,6 +65,8 @@ deque<pair<int64, CInv> > vRelayExpiration; | |||
| 62 | CCriticalSection cs_mapRelay; | 65 | CCriticalSection cs_mapRelay; |
| 63 | map<CInv, int64> mapAlreadyAskedFor; | 66 | map<CInv, int64> mapAlreadyAskedFor; |
| 64 | 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; | ||
| 65 | 70 | ||
| 66 | int nPeersWatched = 0; | 71 | int nPeersWatched = 0; |
| 67 | int64 nBlocksReceived = 0; | 72 | int64 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 | ||
| 176 | static string SockAccountingText() | 181 | static 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. |
| 626 | static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting, | 657 | static 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 | ||
| 924 | static 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 | |||
| 885 | static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char pk[32], | 945 | static 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. |
| 973 | CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting, | 1074 | CNode* 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(); |