Skip to content

Commit 272c951

Browse files
5699158 merge bitcoin#29833: fix and improve logs (Kittywhiskers Van Gogh) 95a1853 merge bitcoin#30085: detect addnode cjdns peers in GetAddedNodeInfo() (Kittywhiskers Van Gogh) 9d959d7 merge bitcoin#29813: improve `-i2pacceptincoming` mention (Kittywhiskers Van Gogh) 5045fa3 merge bitcoin#28692: Delete i2p fuzz test (Kittywhiskers Van Gogh) 7b01e8b merge bitcoin#28077: also sleep after errors in Accept() & destroy the session if we get an unexpected error (Kittywhiskers Van Gogh) 0c42410 merge bitcoin#27071: Handle CJDNS from LookupSubNet() (Kittywhiskers Van Gogh) 821c11f merge bitcoin#28078: remove unneeded exports, use helpers over low-level code, use optional (Kittywhiskers Van Gogh) d051929 refactor: replace external `::GetLocal()` usage (Kittywhiskers Van Gogh) 481175f merge bitcoin#27719: remove Tor link & generalize onion getnodeaddresses RPC (Kittywhiskers Van Gogh) 378ad01 merge bitcoin#25989: abort if i2p/cjdns are chosen via -onlynet but are unreachable (Kittywhiskers Van Gogh) 8b23bfb partial bitcoin#24356: replace CConnman::SocketEvents() with mockable Sock::WaitMany() (Kittywhiskers Van Gogh) 1a64e8d merge bitcoin#25286: remove duplicate categories from LogPrint output (Kittywhiskers Van Gogh) Pull request description: ## Breaking Changes None expected. ## Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas **(note: N/A)** - [x] I have added or updated relevant unit/integration/functional/e2e tests - [x] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ ACKs for top commit: UdjinM6: utACK 5699158 PastaPastaPasta: utACK 5699158 Tree-SHA512: b1ffc310574de5ec40d18aa4a453ef328d8f935c42d43a204c14fa264f099a106ddea793a018f56dcf75d9548fb06d1580c6aa1d90f66afa95089435e0b9606d
2 parents 7e584f6 + 5699158 commit 272c951

31 files changed

+495
-395
lines changed

doc/cjdns.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,4 @@ There are several ways to see your CJDNS address in Dash Core:
9191
To see which CJDNS peers your node is connected to, use `dash-cli -netinfo 4`
9292
or the `getpeerinfo` RPC (i.e. `dash-cli getpeerinfo`).
9393

94-
To see which CJDNS addresses your node knows, use the `getnodeaddresses 0 cjdns`
95-
RPC.
94+
You can use the `getnodeaddresses` RPC to fetch a number of CJDNS peers known to your node; run `dash-cli help getnodeaddresses` for details.

doc/i2p.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ one of the networks has issues.
7979
## Persistent vs transient I2P addresses
8080

8181
The first time Dash Core connects to the I2P router, it automatically
82-
generates a persistent I2P address and its corresponding private key by default
83-
or if `-i2pacceptincoming=1` is set. The private key is saved in a file named
82+
generates a persistent I2P address and its corresponding private key by default,
83+
unless `-i2pacceptincoming=0` is set. The private key is saved in a file named
8484
`i2p_private_key` in the Dash Core data directory. The persistent I2P
8585
address is used for making outbound connections and accepting inbound
8686
connections.
@@ -109,8 +109,7 @@ incoming I2P connections (`-i2pacceptincoming`):
109109
To see which I2P peers your node is connected to, use `dash-cli -netinfo 4`
110110
or the `getpeerinfo` RPC (e.g. `dash-cli getpeerinfo`).
111111

112-
To see which I2P addresses your node knows, use the `getnodeaddresses 0 i2p`
113-
RPC.
112+
You can use the `getnodeaddresses` RPC to fetch a number of I2P peers known to your node; run `dash-cli help getnodeaddresses` for details.
114113

115114
## Compatibility
116115

doc/tor.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,7 @@
22

33
It is possible to run Dash Core as a Tor onion service, and connect to such services.
44

5-
The following directions assume you have a Tor proxy running on port 9050. Many
6-
distributions default to having a SOCKS proxy listening on port 9050, but others
7-
may not. In particular, the Tor Browser Bundle defaults to listening on port 9150.
8-
See [Tor Project FAQ:TBBSocksPort](https://www.torproject.org/docs/faq.html.en#TBBSocksPort)
9-
for how to properly configure Tor.
5+
The following directions assume you have a Tor proxy running on port 9050. Many distributions default to having a SOCKS proxy listening on port 9050, but others may not. In particular, the Tor Browser Bundle defaults to listening on port 9150.
106

117
## Compatibility
128

@@ -30,8 +26,7 @@ CLI `-addrinfo` returns the number of addresses known to your node per
3026
network. This can be useful to see how many onion peers your node knows,
3127
e.g. for `-onlynet=onion`.
3228

33-
To fetch a number of onion addresses that your node knows, for example seven
34-
addresses, use the `getnodeaddresses 7 onion` RPC.
29+
You can use the `getnodeaddresses` RPC to fetch a number of onion peers known to your node; run `dash-cli help getnodeaddresses` for details.
3530

3631
## 1. Run Dash Core behind a Tor proxy
3732

src/Makefile.test.include

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,6 @@ test_fuzz_fuzz_SOURCES = \
289289
test/fuzz/golomb_rice.cpp \
290290
test/fuzz/hex.cpp \
291291
test/fuzz/http_request.cpp \
292-
test/fuzz/i2p.cpp \
293292
test/fuzz/integer.cpp \
294293
test/fuzz/key.cpp \
295294
test/fuzz/key_io.cpp \

src/httpserver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ CService HTTPRequest::GetPeer() const
653653
evhttp_connection_get_peer(con, (char**)&address, &port);
654654
#endif // HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR
655655

656-
peer = LookupNumeric(address, port);
656+
peer = MaybeFlipIPv6toCJDNS(LookupNumeric(address, port));
657657
}
658658
return peer;
659659
}

src/i2p.cpp

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <netaddress.h>
1313
#include <netbase.h>
1414
#include <random.h>
15+
#include <sync.h>
1516
#include <tinyformat.h>
1617
#include <util/readwritefile.h>
1718
#include <util/sock.h>
@@ -146,35 +147,71 @@ bool Session::Listen(Connection& conn)
146147
conn.sock = StreamAccept();
147148
return true;
148149
} catch (const std::runtime_error& e) {
149-
Log("Error listening: %s", e.what());
150+
LogPrintLevel(BCLog::I2P, BCLog::Level::Error, "Couldn't listen: %s\n", e.what());
150151
CheckControlSock();
151152
}
152153
return false;
153154
}
154155

155156
bool Session::Accept(Connection& conn)
156157
{
157-
try {
158-
while (!*m_interrupt) {
159-
Sock::Event occurred;
160-
if (!conn.sock->Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred)) {
161-
throw std::runtime_error("wait on socket failed");
162-
}
158+
AssertLockNotHeld(m_mutex);
163159

164-
if ((occurred & Sock::RECV) == 0) {
165-
// Timeout, no incoming connections within MAX_WAIT_FOR_IO.
166-
continue;
167-
}
160+
std::string errmsg;
161+
bool disconnect{false};
162+
163+
while (!*m_interrupt) {
164+
Sock::Event occurred;
165+
if (!conn.sock->Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred)) {
166+
errmsg = "wait on socket failed";
167+
break;
168+
}
168169

169-
const std::string& peer_dest =
170-
conn.sock->RecvUntilTerminator('\n', MAX_WAIT_FOR_IO, *m_interrupt, MAX_MSG_SIZE);
170+
if (occurred == 0) {
171+
// Timeout, no incoming connections or errors within MAX_WAIT_FOR_IO.
172+
continue;
173+
}
171174

172-
conn.peer = CService(DestB64ToAddr(peer_dest), I2P_SAM31_PORT);
175+
std::string peer_dest;
176+
try {
177+
peer_dest = conn.sock->RecvUntilTerminator('\n', MAX_WAIT_FOR_IO, *m_interrupt, MAX_MSG_SIZE);
178+
} catch (const std::runtime_error& e) {
179+
errmsg = e.what();
180+
break;
181+
}
173182

174-
return true;
183+
CNetAddr peer_addr;
184+
try {
185+
peer_addr = DestB64ToAddr(peer_dest);
186+
} catch (const std::runtime_error& e) {
187+
// The I2P router is expected to send the Base64 of the connecting peer,
188+
// but it may happen that something like this is sent instead:
189+
// STREAM STATUS RESULT=I2P_ERROR MESSAGE="Session was closed"
190+
// In that case consider the session damaged and close it right away,
191+
// even if the control socket is alive.
192+
if (peer_dest.find("RESULT=I2P_ERROR") != std::string::npos) {
193+
errmsg = strprintf("unexpected reply that hints the session is unusable: %s", peer_dest);
194+
disconnect = true;
195+
} else {
196+
errmsg = e.what();
197+
}
198+
break;
175199
}
176-
} catch (const std::runtime_error& e) {
177-
Log("Error accepting: %s", e.what());
200+
201+
conn.peer = CService(peer_addr, I2P_SAM31_PORT);
202+
203+
return true;
204+
}
205+
206+
if (*m_interrupt) {
207+
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Accept was interrupted\n");
208+
} else {
209+
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Error accepting%s: %s\n", disconnect ? " (will close the session)" : "", errmsg);
210+
}
211+
if (disconnect) {
212+
LOCK(m_mutex);
213+
Disconnect();
214+
} else {
178215
CheckControlSock();
179216
}
180217
return false;
@@ -185,7 +222,7 @@ bool Session::Connect(const CService& to, Connection& conn, bool& proxy_error)
185222
// Refuse connecting to arbitrary ports. We don't specify any destination port to the SAM proxy
186223
// when connecting (SAM 3.1 does not use ports) and it forces/defaults it to I2P_SAM31_PORT.
187224
if (to.GetPort() != I2P_SAM31_PORT) {
188-
Log("Error connecting to %s, connection refused due to arbitrary port %s", to.ToStringAddrPort(), to.GetPort());
225+
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Error connecting to %s, connection refused due to arbitrary port %s\n", to.ToStringAddrPort(), to.GetPort());
189226
proxy_error = false;
190227
return false;
191228
}
@@ -233,7 +270,7 @@ bool Session::Connect(const CService& to, Connection& conn, bool& proxy_error)
233270

234271
throw std::runtime_error(strprintf("\"%s\"", connect_reply.full));
235272
} catch (const std::runtime_error& e) {
236-
Log("Error connecting to %s: %s", to.ToStringAddrPort(), e.what());
273+
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Error connecting to %s: %s\n", to.ToStringAddrPort(), e.what());
237274
CheckControlSock();
238275
return false;
239276
}
@@ -251,12 +288,6 @@ std::string Session::Reply::Get(const std::string& key) const
251288
return pos->second.value();
252289
}
253290

254-
template <typename... Args>
255-
void Session::Log(const std::string& fmt, const Args&... args) const
256-
{
257-
LogPrint(BCLog::I2P, "I2P: %s\n", tfm::format(fmt, args...));
258-
}
259-
260291
Session::Reply Session::SendRequestAndGetReply(const Sock& sock,
261292
const std::string& request,
262293
bool check_result_ok) const
@@ -316,7 +347,7 @@ void Session::CheckControlSock()
316347

317348
std::string errmsg;
318349
if (!m_control_sock->IsConnected(errmsg)) {
319-
Log("Control socket error: %s", errmsg);
350+
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Control socket error: %s\n", errmsg);
320351
Disconnect();
321352
}
322353
}
@@ -371,7 +402,7 @@ void Session::CreateIfNotCreatedAlready()
371402
const auto session_type = m_transient ? "transient" : "persistent";
372403
const auto session_id = GetRandHash().GetHex().substr(0, 10); // full is overkill, too verbose in the logs
373404

374-
Log("Creating %s SAM session %s with %s", session_type, session_id, m_control_host.ToStringAddrPort());
405+
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Creating %s SAM session %s with %s\n", session_type, session_id, m_control_host.ToStringAddrPort());
375406

376407
auto sock = Hello();
377408

@@ -408,7 +439,7 @@ void Session::CreateIfNotCreatedAlready()
408439
m_session_id = session_id;
409440
m_control_sock = std::move(sock);
410441

411-
Log("%s SAM session %s created, my address=%s",
442+
LogPrintLevel(BCLog::I2P, BCLog::Level::Info, "%s SAM session %s created, my address=%s\n",
412443
Capitalize(session_type),
413444
m_session_id,
414445
m_my_addr.ToStringAddrPort());
@@ -439,9 +470,9 @@ void Session::Disconnect()
439470
{
440471
if (m_control_sock->Get() != INVALID_SOCKET) {
441472
if (m_session_id.empty()) {
442-
Log("Destroying incomplete SAM session");
473+
LogPrintLevel(BCLog::I2P, BCLog::Level::Info, "Destroying incomplete SAM session\n");
443474
} else {
444-
Log("Destroying SAM session %s", m_session_id);
475+
LogPrintLevel(BCLog::I2P, BCLog::Level::Info, "Destroying SAM session %s\n", m_session_id);
445476
}
446477
}
447478
m_control_sock = std::make_unique<Sock>(INVALID_SOCKET);

src/i2p.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ class Session
105105
* completion the `peer` member will be set to the address of the incoming peer.
106106
* @return true on success
107107
*/
108-
bool Accept(Connection& conn);
108+
bool Accept(Connection& conn) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
109109

110110
/**
111111
* Connect to an I2P peer.
@@ -155,14 +155,6 @@ class Session
155155
std::string Get(const std::string& key) const;
156156
};
157157

158-
/**
159-
* Log a message in the `BCLog::I2P` category.
160-
* @param[in] fmt printf(3)-like format string.
161-
* @param[in] args printf(3)-like arguments that correspond to `fmt`.
162-
*/
163-
template <typename... Args>
164-
void Log(const std::string& fmt, const Args&... args) const;
165-
166158
/**
167159
* Send request and get a reply from the SAM proxy.
168160
* @param[in] sock A socket that is connected to the SAM proxy.

src/init.cpp

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,33 +1694,32 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
16941694
}
16951695

16961696
if (args.IsArgSet("-onlynet")) {
1697-
std::set<enum Network> nets;
1697+
g_reachable_nets.RemoveAll();
16981698
for (const std::string& snet : args.GetArgs("-onlynet")) {
16991699
enum Network net = ParseNetwork(snet);
17001700
if (net == NET_UNROUTABLE)
17011701
return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet));
1702-
nets.insert(net);
1703-
}
1704-
for (int n = 0; n < NET_MAX; n++) {
1705-
enum Network net = (enum Network)n;
1706-
assert(IsReachable(net));
1707-
if (!nets.count(net))
1708-
SetReachable(net, false);
1702+
g_reachable_nets.Add(net);
17091703
}
17101704
}
17111705

17121706
if (!args.IsArgSet("-cjdnsreachable")) {
1713-
SetReachable(NET_CJDNS, false);
1707+
if (args.IsArgSet("-onlynet") && g_reachable_nets.Contains(NET_CJDNS)) {
1708+
return InitError(
1709+
_("Outbound connections restricted to CJDNS (-onlynet=cjdns) but "
1710+
"-cjdnsreachable is not provided"));
1711+
}
1712+
g_reachable_nets.Remove(NET_CJDNS);
17141713
}
1715-
// Now IsReachable(NET_CJDNS) is true if:
1714+
// Now g_reachable_nets.Contains(NET_CJDNS) is true if:
17161715
// 1. -cjdnsreachable is given and
17171716
// 2.1. -onlynet is not given or
17181717
// 2.2. -onlynet=cjdns is given
17191718

17201719
// Requesting DNS seeds entails connecting to IPv4/IPv6, which -onlynet options may prohibit:
17211720
// If -dnsseed=1 is explicitly specified, abort. If it's left unspecified by the user, we skip
17221721
// the DNS seeds by adjusting -dnsseed in InitParameterInteraction.
1723-
if (args.GetBoolArg("-dnsseed", DEFAULT_DNSSEED) == true && !IsReachable(NET_IPV4) && !IsReachable(NET_IPV6)) {
1722+
if (args.GetBoolArg("-dnsseed", DEFAULT_DNSSEED) == true && !g_reachable_nets.Contains(NET_IPV4) && !g_reachable_nets.Contains(NET_IPV6)) {
17241723
return InitError(strprintf(_("Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6")));
17251724
};
17261725

@@ -1750,7 +1749,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
17501749
onion_proxy = addrProxy;
17511750
}
17521751

1753-
const bool onlynet_used_with_onion{args.IsArgSet("-onlynet") && IsReachable(NET_ONION)};
1752+
const bool onlynet_used_with_onion{args.IsArgSet("-onlynet") && g_reachable_nets.Contains(NET_ONION)};
17541753

17551754
// -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses
17561755
// -noonion (or -onion=0) disables connecting to .onion entirely
@@ -1785,7 +1784,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
17851784
"reaching the Tor network is not provided: none of -proxy, -onion or "
17861785
"-listenonion is given"));
17871786
}
1788-
SetReachable(NET_ONION, false);
1787+
g_reachable_nets.Remove(NET_ONION);
17891788
}
17901789

17911790
for (const std::string& strAddr : args.GetArgs("-externalip")) {
@@ -2412,7 +2411,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
24122411
}
24132412
SetProxy(NET_I2P, Proxy{addr.value()});
24142413
} else {
2415-
SetReachable(NET_I2P, false);
2414+
if (args.IsArgSet("-onlynet") && g_reachable_nets.Contains(NET_I2P)) {
2415+
return InitError(
2416+
_("Outbound connections restricted to i2p (-onlynet=i2p) but "
2417+
"-i2psam is not provided"));
2418+
}
2419+
g_reachable_nets.Remove(NET_I2P);
24162420
}
24172421

24182422
connOptions.m_i2p_accept_incoming = args.GetBoolArg("-i2pacceptincoming", DEFAULT_I2P_ACCEPT_INCOMING);

src/masternode/node.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,14 @@ bool CActiveMasternodeManager::GetLocalAddress(CService& addrRet)
239239
if (!fFoundLocal) {
240240
bool empty = true;
241241
// If we have some peers, let's try to find our local address from one of them
242-
auto service = m_info.service;
243242
m_connman.ForEachNodeContinueIf(CConnman::AllNodes, [&](CNode* pnode) {
244243
empty = false;
245-
if (pnode->addr.IsIPv4()) fFoundLocal = GetLocal(service, *pnode) && IsValidNetAddr(service);
244+
if (pnode->addr.IsIPv4()) {
245+
if (auto addr = ::GetLocalAddress(*pnode); IsValidNetAddr(addr)) {
246+
addrRet = addr;
247+
fFoundLocal = true;
248+
}
249+
}
246250
return !fFoundLocal;
247251
});
248252
// nothing and no live connections, can't do anything for now
@@ -257,10 +261,10 @@ bool CActiveMasternodeManager::GetLocalAddress(CService& addrRet)
257261

258262
bool CActiveMasternodeManager::IsValidNetAddr(const CService& addrIn)
259263
{
264+
if (!addrIn.IsValid() || !addrIn.IsIPv4()) return false;
260265
// TODO: regtest is fine with any addresses for now,
261266
// should probably be a bit smarter if one day we start to implement tests for this
262-
return !Params().RequireRoutableExternalIP() ||
263-
(addrIn.IsIPv4() && IsReachable(addrIn) && addrIn.IsRoutable());
267+
return !Params().RequireRoutableExternalIP() || (g_reachable_nets.Contains(addrIn) && addrIn.IsRoutable());
264268
}
265269

266270
template <template <typename> class EncryptedObj, typename Obj>

0 commit comments

Comments
 (0)