mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-06 18:53:21 +01:00
i2p: destroy the session if we get an unexpected error from the I2P router
From https://geti2p.net/en/docs/api/samv3: If SILENT=false was passed, which is the default value, the SAM bridge sends the client a ASCII line containing the base64 public destination key of the requesting peer So, `Accept()` is supposed to receive a Base64 encoded destination of the connecting peer, but if it receives something like this instead: STREAM STATUS RESULT=I2P_ERROR MESSAGE="Session was closed" then destroy the session.
This commit is contained in:
69
src/i2p.cpp
69
src/i2p.cpp
@@ -12,6 +12,7 @@
|
||||
#include <netaddress.h>
|
||||
#include <netbase.h>
|
||||
#include <random.h>
|
||||
#include <sync.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/fs.h>
|
||||
#include <util/readwritefile.h>
|
||||
@@ -153,27 +154,59 @@ bool Session::Listen(Connection& conn)
|
||||
|
||||
bool Session::Accept(Connection& conn)
|
||||
{
|
||||
try {
|
||||
while (!*m_interrupt) {
|
||||
Sock::Event occurred;
|
||||
if (!conn.sock->Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred)) {
|
||||
throw std::runtime_error("wait on socket failed");
|
||||
}
|
||||
AssertLockNotHeld(m_mutex);
|
||||
|
||||
if (occurred == 0) {
|
||||
// Timeout, no incoming connections or errors within MAX_WAIT_FOR_IO.
|
||||
continue;
|
||||
}
|
||||
std::string errmsg;
|
||||
bool disconnect{false};
|
||||
|
||||
const std::string& peer_dest =
|
||||
conn.sock->RecvUntilTerminator('\n', MAX_WAIT_FOR_IO, *m_interrupt, MAX_MSG_SIZE);
|
||||
|
||||
conn.peer = CService(DestB64ToAddr(peer_dest), I2P_SAM31_PORT);
|
||||
|
||||
return true;
|
||||
while (!*m_interrupt) {
|
||||
Sock::Event occurred;
|
||||
if (!conn.sock->Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred)) {
|
||||
errmsg = "wait on socket failed";
|
||||
break;
|
||||
}
|
||||
} catch (const std::runtime_error& e) {
|
||||
Log("Error accepting: %s", e.what());
|
||||
|
||||
if (occurred == 0) {
|
||||
// Timeout, no incoming connections or errors within MAX_WAIT_FOR_IO.
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string peer_dest;
|
||||
try {
|
||||
peer_dest = conn.sock->RecvUntilTerminator('\n', MAX_WAIT_FOR_IO, *m_interrupt, MAX_MSG_SIZE);
|
||||
} catch (const std::runtime_error& e) {
|
||||
errmsg = e.what();
|
||||
break;
|
||||
}
|
||||
|
||||
CNetAddr peer_addr;
|
||||
try {
|
||||
peer_addr = DestB64ToAddr(peer_dest);
|
||||
} catch (const std::runtime_error& e) {
|
||||
// The I2P router is expected to send the Base64 of the connecting peer,
|
||||
// but it may happen that something like this is sent instead:
|
||||
// STREAM STATUS RESULT=I2P_ERROR MESSAGE="Session was closed"
|
||||
// In that case consider the session damaged and close it right away,
|
||||
// even if the control socket is alive.
|
||||
if (peer_dest.find("RESULT=I2P_ERROR") != std::string::npos) {
|
||||
errmsg = strprintf("unexpected reply that hints the session is unusable: %s", peer_dest);
|
||||
disconnect = true;
|
||||
} else {
|
||||
errmsg = e.what();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
conn.peer = CService(peer_addr, I2P_SAM31_PORT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Log("Error accepting%s: %s", disconnect ? " (will close the session)" : "", errmsg);
|
||||
if (disconnect) {
|
||||
LOCK(m_mutex);
|
||||
Disconnect();
|
||||
} else {
|
||||
CheckControlSock();
|
||||
}
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user