Skip to content

Commit 2b781ad

Browse files
committed
i2p: add support for creating transient sessions
Instead of providing our destination (private key) to the I2P proxy when creating the session, ask it to generate one for us and do not save it on disk.
1 parent c012875 commit 2b781ad

File tree

3 files changed

+64
-16
lines changed

3 files changed

+64
-16
lines changed

src/i2p.cpp

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
#include <netaddress.h>
1313
#include <netbase.h>
1414
#include <random.h>
15-
#include <util/strencodings.h>
1615
#include <tinyformat.h>
1716
#include <util/readwritefile.h>
1817
#include <util/sock.h>
1918
#include <util/spanparsing.h>
19+
#include <util/strencodings.h>
2020
#include <util/system.h>
2121

2222
#include <chrono>
@@ -115,8 +115,19 @@ namespace sam {
115115
Session::Session(const fs::path& private_key_file,
116116
const CService& control_host,
117117
CThreadInterrupt* interrupt)
118-
: m_private_key_file(private_key_file), m_control_host(control_host), m_interrupt(interrupt),
119-
m_control_sock(std::make_unique<Sock>(INVALID_SOCKET))
118+
: m_private_key_file{private_key_file},
119+
m_control_host{control_host},
120+
m_interrupt{interrupt},
121+
m_control_sock{std::make_unique<Sock>(INVALID_SOCKET)},
122+
m_transient{false}
123+
{
124+
}
125+
126+
Session::Session(const CService& control_host, CThreadInterrupt* interrupt)
127+
: m_control_host{control_host},
128+
m_interrupt{interrupt},
129+
m_control_sock{std::make_unique<Sock>(INVALID_SOCKET)},
130+
m_transient{true}
120131
{
121132
}
122133

@@ -355,29 +366,47 @@ void Session::CreateIfNotCreatedAlready()
355366
return;
356367
}
357368

358-
Log("Creating SAM session with %s", m_control_host.ToString());
369+
const auto session_type = m_transient ? "transient" : "persistent";
370+
const auto session_id = GetRandHash().GetHex().substr(0, 10); // full is overkill, too verbose in the logs
371+
372+
Log("Creating %s SAM session %s with %s", session_type, session_id, m_control_host.ToString());
359373

360374
auto sock = Hello();
361375

362-
const auto& [read_ok, data] = ReadBinaryFile(m_private_key_file);
363-
if (read_ok) {
364-
m_private_key.assign(data.begin(), data.end());
376+
if (m_transient) {
377+
// The destination (private key) is generated upon session creation and returned
378+
// in the reply in DESTINATION=.
379+
const Reply& reply = SendRequestAndGetReply(
380+
*sock,
381+
strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT", session_id));
382+
383+
m_private_key = DecodeI2PBase64(reply.Get("DESTINATION"));
365384
} else {
366-
GenerateAndSavePrivateKey(*sock);
367-
}
385+
// Read our persistent destination (private key) from disk or generate
386+
// one and save it to disk. Then use it when creating the session.
387+
const auto& [read_ok, data] = ReadBinaryFile(m_private_key_file);
388+
if (read_ok) {
389+
m_private_key.assign(data.begin(), data.end());
390+
} else {
391+
GenerateAndSavePrivateKey(*sock);
392+
}
368393

369-
const std::string& session_id = GetRandHash().GetHex().substr(0, 10); // full is an overkill, too verbose in the logs
370-
const std::string& private_key_b64 = SwapBase64(EncodeBase64(m_private_key));
394+
const std::string& private_key_b64 = SwapBase64(EncodeBase64(m_private_key));
371395

372-
SendRequestAndGetReply(*sock, strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s",
373-
session_id, private_key_b64));
396+
SendRequestAndGetReply(*sock,
397+
strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s",
398+
session_id,
399+
private_key_b64));
400+
}
374401

375402
m_my_addr = CService(DestBinToAddr(MyDestination()), I2P_SAM31_PORT);
376403
m_session_id = session_id;
377404
m_control_sock = std::move(sock);
378405

379-
LogPrintfCategory(BCLog::I2P, "SAM session created: session id=%s, my address=%s\n",
380-
m_session_id, m_my_addr.ToString());
406+
Log("%s SAM session %s created, my address=%s",
407+
Capitalize(session_type),
408+
m_session_id,
409+
m_my_addr.ToString());
381410
}
382411

383412
std::unique_ptr<Sock> Session::StreamAccept()

src/i2p.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,19 @@ class Session
7070
const CService& control_host,
7171
CThreadInterrupt* interrupt);
7272

73+
/**
74+
* Construct a transient session which will generate its own I2P private key
75+
* rather than read the one from disk (it will not be saved on disk either and
76+
* will be lost once this object is destroyed). This will not initiate any IO,
77+
* the session will be lazily created later when first used.
78+
* @param[in] control_host Location of the SAM proxy.
79+
* @param[in,out] interrupt If this is signaled then all operations are canceled as soon as
80+
* possible and executing methods throw an exception. Notice: only a pointer to the
81+
* `CThreadInterrupt` object is saved, so it must not be destroyed earlier than this
82+
* `Session` object.
83+
*/
84+
Session(const CService& control_host, CThreadInterrupt* interrupt);
85+
7386
/**
7487
* Destroy the session, closing the internally used sockets. The sockets that have been
7588
* returned by `Accept()` or `Connect()` will not be closed, but they will be closed by
@@ -262,6 +275,12 @@ class Session
262275
* SAM session id.
263276
*/
264277
std::string m_session_id GUARDED_BY(m_mutex);
278+
279+
/**
280+
* Whether this is a transient session (the I2P private key will not be
281+
* read or written to disk).
282+
*/
283+
const bool m_transient;
265284
};
266285

267286
} // namespace sam

src/test/i2p_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE(unlimited_recv)
3030
i2p::sam::Session session(gArgs.GetDataDirNet() / "test_i2p_private_key", CService{}, &interrupt);
3131

3232
{
33-
ASSERT_DEBUG_LOG("Creating SAM session");
33+
ASSERT_DEBUG_LOG("Creating persistent SAM session");
3434
ASSERT_DEBUG_LOG("too many bytes without a terminator");
3535

3636
i2p::Connection conn;

0 commit comments

Comments
 (0)