From af6c154f59ab95b19af0b30dfe5ddf58e44d3112 Mon Sep 17 00:00:00 2001 From: anonimal Date: Sat, 11 Nov 2017 00:16:15 +0000 Subject: [PATCH 01/10] Core: refactor context into core namespace Resolves TODOs + brings us closer to removing the singleton. --- src/client/api/i2p_control/session.cc | 6 ++-- src/client/reseed.cc | 2 +- src/client/reseed.h | 2 +- src/client/util/http.cc | 2 +- src/core/instance.cc | 1 - src/core/router/context.cc | 8 +++-- src/core/router/context.h | 8 +++-- src/core/router/i2np.cc | 12 +++---- src/core/router/net_db/impl.cc | 8 ++--- src/core/router/net_db/requests.cc | 2 +- src/core/router/transports/impl.cc | 8 ++--- src/core/router/transports/ntcp/session.cc | 12 +++---- src/core/router/transports/ssu/server.cc | 12 +++---- src/core/router/transports/ssu/session.cc | 40 +++++++++++----------- src/core/router/transports/upnp.cc | 2 +- src/core/router/tunnel/config.cc | 2 +- src/core/router/tunnel/endpoint.cc | 2 +- src/core/router/tunnel/impl.cc | 4 +-- src/core/router/tunnel/pool.cc | 4 +-- 19 files changed, 70 insertions(+), 67 deletions(-) diff --git a/src/client/api/i2p_control/session.cc b/src/client/api/i2p_control/session.cc index bba52b60..cf5a8ea2 100644 --- a/src/client/api/i2p_control/session.cc +++ b/src/client/api/i2p_control/session.cc @@ -248,7 +248,7 @@ void I2PControlSession::HandleRouterInfo( case RouterInfo::Uptime: response->SetParam( pair.first, - static_cast(kovri::context.GetUptime()) * 1000); + static_cast(core::context.GetUptime()) * 1000); break; case RouterInfo::Version: @@ -273,7 +273,7 @@ void I2PControlSession::HandleRouterInfo( case RouterInfo::NetStatus: response->SetParam( pair.first, - static_cast(kovri::context.GetStatus())); + static_cast(core::context.GetStatus())); break; case RouterInfo::TunnelsParticipating: @@ -393,7 +393,7 @@ void I2PControlSession::HandleShutdown(Response* response) void I2PControlSession::HandleShutdownGraceful(Response* response) { // Stop accepting tunnels - kovri::context.SetAcceptsTunnels(false); + core::context.SetAcceptsTunnels(false); // Get tunnel expiry time std::uint64_t timeout = kovri::core::tunnels.GetTransitTunnelsExpirationTimeout(); LOG(info) diff --git a/src/client/reseed.cc b/src/client/reseed.cc index e4bc86af..4a7e9434 100644 --- a/src/client/reseed.cc +++ b/src/client/reseed.cc @@ -239,7 +239,7 @@ bool Reseed::FetchStream( */ bool SU3::SU3Impl() { - if (kovri::context.GetOptionDisableSU3Verification()) + if (core::context.GetOptionDisableSU3Verification()) { LOG(warning) << "SU3: verification disabled !"; // TODO(unassigned): detection and implemention of other formats diff --git a/src/client/reseed.h b/src/client/reseed.h index 919fe5f7..dc9c4e8f 100644 --- a/src/client/reseed.h +++ b/src/client/reseed.h @@ -69,7 +69,7 @@ class Reseed { public: /// @brief Constructs stream from string explicit Reseed( - const std::string& stream = kovri::context.GetOptionReseedFrom()) + const std::string& stream = core::context.GetOptionReseedFrom()) : m_Stream(stream) {} /// @brief Reseed implementation diff --git a/src/client/util/http.cc b/src/client/util/http.cc index 33394ef8..b501697b 100644 --- a/src/client/util/http.cc +++ b/src/client/util/http.cc @@ -117,7 +117,7 @@ bool HTTP::DownloadViaClearnet() { LOG(debug) << "HTTP: Download Clearnet with timeout : " << kovri::core::GetType(Timeout::Request); // Ensure that we only download from explicit SSL-enabled hosts - if (kovri::context.GetOptionEnableSSL()) { + if (core::context.GetOptionEnableSSL()) { const std::string cert = uri.host() + ".crt"; const boost::filesystem::path cert_path = kovri::core::GetSSLCertsPath() / cert; if (!boost::filesystem::exists(cert_path)) { diff --git a/src/core/instance.cc b/src/core/instance.cc index 17e811b9..8f31e1da 100644 --- a/src/core/instance.cc +++ b/src/core/instance.cc @@ -95,7 +95,6 @@ void Instance::Initialize() : map["port"].as(); LOG(info) << "Instance: listening on port " << port; - // TODO(unassigned): context should be in core namespace (see TODO in router context) context.Init(host, port); context.UpdatePort(port); diff --git a/src/core/router/context.cc b/src/core/router/context.cc index 1ca4b93b..59854776 100644 --- a/src/core/router/context.cc +++ b/src/core/router/context.cc @@ -45,9 +45,10 @@ #include "version.h" -namespace kovri { -// TODO(anonimal): this belongs in core namespace - +namespace kovri +{ +namespace core +{ // Simply instantiating in namespace scope ties into, and is limited by, the current singleton design // TODO(unassigned): refactoring this requires global work but will help to remove the singleton RouterContext context; @@ -385,4 +386,5 @@ std::uint32_t RouterContext::GetUptime() const { return kovri::core::GetSecondsSinceEpoch () - m_StartupTime; } +} // namespace core } // namespace kovri diff --git a/src/core/router/context.h b/src/core/router/context.h index 7fef8589..a24587d3 100644 --- a/src/core/router/context.h +++ b/src/core/router/context.h @@ -46,9 +46,10 @@ #include "core/router/identity.h" #include "core/router/info.h" -namespace kovri { -// TODO(anonimal): this belongs in core namespace - +namespace kovri +{ +namespace core +{ const char ROUTER_INFO[] = "router.info"; const char ROUTER_KEYS[] = "router.keys"; const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes @@ -336,6 +337,7 @@ class RouterContext : public kovri::core::GarlicDestination { extern RouterContext context; +} // namespace core } // namespace kovri #endif // SRC_CORE_ROUTER_CONTEXT_H_ diff --git a/src/core/router/i2np.cc b/src/core/router/i2np.cc index 275f5ca4..55a7d123 100644 --- a/src/core/router/i2np.cc +++ b/src/core/router/i2np.cc @@ -241,7 +241,7 @@ std::shared_ptr CreateDatabaseSearchReply( memcpy(buf + len, it, 32); len += 32; } - memcpy(buf + len, kovri::context.GetRouterInfo().GetIdentHash(), 32); + memcpy(buf + len, context.GetRouterInfo().GetIdentHash(), 32); len += 32; m->len += len; m->FillI2NPMessageHeader(I2NPDatabaseSearchReply); @@ -346,12 +346,12 @@ bool HandleBuildRequestRecords( // Test if current hop's router identity is ours if (!memcmp( record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, - (const std::uint8_t *)kovri::context.GetRouterInfo().GetIdentHash(), + (const std::uint8_t *)context.GetRouterInfo().GetIdentHash(), 16)) { LOG(debug) << "I2NPMessage: record " << i << " is ours"; // Get session key from encrypted block kovri::core::ElGamalDecrypt( - kovri::context.GetEncryptionPrivateKey(), + context.GetEncryptionPrivateKey(), record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clear_text); /** @@ -362,7 +362,7 @@ bool HandleBuildRequestRecords( * participate in the tunnel, and higher values meaning * higher levels of rejection. */ - if (kovri::context.AcceptsTunnels() && + if (context.AcceptsTunnels() && kovri::core::tunnels.GetTransitTunnels().size() <= MAX_NUM_TRANSIT_TUNNELS && !kovri::core::transports.IsBandwidthExceeded()) { @@ -704,7 +704,7 @@ void HandleI2NPMessage( LOG(debug) << "I2NPMessage: local destination for garlic doesn't exist anymore"; } else { - kovri::context.ProcessGarlicMessage(msg); + context.ProcessGarlicMessage(msg); } break; } @@ -719,7 +719,7 @@ void HandleI2NPMessage( if (msg->from && msg->from->GetTunnelPool()) msg->from->GetTunnelPool()->ProcessDeliveryStatus(msg); else - kovri::context.ProcessDeliveryStatusMessage(msg); + context.ProcessDeliveryStatusMessage(msg); break; } case I2NPVariableTunnelBuild: diff --git a/src/core/router/net_db/impl.cc b/src/core/router/net_db/impl.cc index 158243c0..7af39c6e 100644 --- a/src/core/router/net_db/impl.cc +++ b/src/core/router/net_db/impl.cc @@ -403,9 +403,9 @@ void NetDb::SaveUpdated() { // if the router count is greater than the threshold check, and the router // is no longer starting up, then continue to check for unreachable routers } else if (total > Size::RouterUnreachableThreshold - && ts > (kovri::context.GetStartupTime() + && ts > (context.GetStartupTime() + Time::RouterStartupPeriod) * 1000LL) { - if (kovri::context.IsFloodfill()) { + if (context.IsFloodfill()) { if (ts > it.second->GetTimestamp() + Time::RouterExpiration) { it.second->SetUnreachable(true); @@ -833,7 +833,7 @@ void NetDb::Publish() { std::set excluded; // TODO(unassigned): fill up later for (std::uint8_t i = 0; i < 2; i++) { // TODO(anonimal): enumerate auto floodfill = GetClosestFloodfill( - kovri::context.GetRouterInfo().GetIdentHash(), + context.GetRouterInfo().GetIdentHash(), excluded); if (floodfill) { std::uint32_t reply_token = kovri::core::Rand(); @@ -844,7 +844,7 @@ void NetDb::Publish() { kovri::core::transports.SendMessage( floodfill->GetIdentHash(), CreateDatabaseStoreMsg( - kovri::context.GetSharedRouterInfo(), + context.GetSharedRouterInfo(), reply_token)); excluded.insert(floodfill->GetIdentHash()); } diff --git a/src/core/router/net_db/requests.cc b/src/core/router/net_db/requests.cc index 730e5e50..a0cdc660 100644 --- a/src/core/router/net_db/requests.cc +++ b/src/core/router/net_db/requests.cc @@ -58,7 +58,7 @@ std::shared_ptr RequestedDestination::CreateRequestMessage( const IdentHash& floodfill) { auto msg = kovri::core::CreateRouterInfoDatabaseLookupMsg( m_Destination, - kovri::context.GetRouterInfo().GetIdentHash(), + context.GetRouterInfo().GetIdentHash(), 0, false, &m_ExcludedPeers); diff --git a/src/core/router/transports/impl.cc b/src/core/router/transports/impl.cc index 298ada80..8e0d8f2e 100644 --- a/src/core/router/transports/impl.cc +++ b/src/core/router/transports/impl.cc @@ -270,7 +270,7 @@ bool Transports::IsBandwidthExceeded() const { LOG(debug) << "Transports: bandwidth has been exceeded"; return true; } - if (kovri::context.GetRouterInfo().HasCap(RouterInfo::Cap::HighBandwidth)) + if (context.GetRouterInfo().HasCap(RouterInfo::Cap::HighBandwidth)) LOG(debug) << "Transports: bandwidth has not been exceeded"; return false; } @@ -299,7 +299,7 @@ void Transports::PostMessages( kovri::core::IdentHash ident, std::vector> msgs) { LOG(debug) << "Transports: posting messages"; - if (ident == kovri::context.GetRouterInfo().GetIdentHash()) { + if (ident == context.GetRouterInfo().GetIdentHash()) { // we send it to ourself for (auto msg : msgs) kovri::core::HandleI2NPMessage(msg); @@ -524,7 +524,7 @@ void Transports::DetectExternalIP() { LOG(error) << "Transports: can't detect external IP, SSU is not available"; return; } - kovri::context.SetStatus(eRouterStatusTesting); + context.SetStatus(eRouterStatusTesting); // TODO(unassigned): Why 5 times? (make constant) for (int i = 0; i < 5; i++) { auto router = kovri::core::netdb.GetRandomPeerTestRouter(); @@ -620,7 +620,7 @@ void Transports::HandlePeerCleanupTimer( } UpdateBandwidth(); // TODO(unassigned): use separate timer(s) for it // if still testing, repeat peer test - if (kovri::context.GetStatus() == eRouterStatusTesting) + if (context.GetStatus() == eRouterStatusTesting) DetectExternalIP(); m_PeerCleanupTimer.expires_from_now( boost::posix_time::seconds( diff --git a/src/core/router/transports/ntcp/session.cc b/src/core/router/transports/ntcp/session.cc index f728e970..1bb5f7b1 100644 --- a/src/core/router/transports/ntcp/session.cc +++ b/src/core/router/transports/ntcp/session.cc @@ -322,11 +322,11 @@ void NTCPSession::CreateAESKey( void NTCPSession::SendPhase3() { LOG(debug) << "NTCPSession:" << GetFormattedSessionInfo() << "*** Phase3, preparing"; - auto keys = kovri::context.GetPrivateKeys(); + auto keys = context.GetPrivateKeys(); std::uint8_t* buf = m_ReceiveBuffer; htobe16buf(buf, keys.GetPublic().GetFullLen()); buf += NTCPSize::Phase3AliceRI; - buf += kovri::context.GetIdentity().ToBuffer(buf, NTCPSize::Buffer); + buf += context.GetIdentity().ToBuffer(buf, NTCPSize::Buffer); std::uint32_t ts_A = htobe32(kovri::core::GetSecondsSinceEpoch()); htobuf32(buf, ts_A); buf += NTCPSize::Phase3AliceTS; @@ -437,7 +437,7 @@ void NTCPSession::HandlePhase4Received( SignedData s; s.Insert(m_Establisher->phase1.pub_key.data(), NTCPSize::PubKey); // x s.Insert(m_Establisher->phase2.pub_key.data(), NTCPSize::PubKey); // y - s.Insert(kovri::context.GetRouterInfo().GetIdentHash(), NTCPSize::Hash); + s.Insert(context.GetRouterInfo().GetIdentHash(), NTCPSize::Hash); s.Insert(ts_A); // Timestamp Alice s.Insert(m_Establisher->phase2.encrypted.timestamp); // Timestamp Bob if (!s.Verify(m_RemoteIdentity, m_ReceiveBuffer)) { @@ -523,7 +523,7 @@ void NTCPSession::HandlePhase1Received( // TODO(anonimal): review if we need to safely break control, ensure exception handling by callers throw; } - const std::uint8_t* ident = kovri::context.GetRouterInfo().GetIdentHash(); + const std::uint8_t* ident = context.GetRouterInfo().GetIdentHash(); for (std::size_t i = 0; i < NTCPSize::Hash; i++) { if ((m_Establisher->phase1.HXxorHI.at(i) ^ ident[i]) != digest.at(i)) { LOG(error) @@ -752,7 +752,7 @@ void NTCPSession::HandlePhase3( SignedData s; s.Insert(m_Establisher->phase1.pub_key.data(), NTCPSize::PubKey); // X s.Insert(m_Establisher->phase2.pub_key.data(), NTCPSize::PubKey); // Y - s.Insert(kovri::context.GetRouterInfo().GetIdentHash(), NTCPSize::Hash); + s.Insert(context.GetRouterInfo().GetIdentHash(), NTCPSize::Hash); s.Insert(ts_A); s.Insert(ts_B); if (!s.Verify(m_RemoteIdentity, buf)) { @@ -782,7 +782,7 @@ void NTCPSession::SendPhase4( s.Insert(m_RemoteIdentity.GetIdentHash(), NTCPSize::Hash); s.Insert(ts_A); s.Insert(ts_B); - auto keys = kovri::context.GetPrivateKeys(); + auto keys = context.GetPrivateKeys(); auto signature_len = keys.GetPublic().GetSignatureLen(); s.Sign(keys, m_ReceiveBuffer); std::size_t padding_size = signature_len & 0x0F; // %16 diff --git a/src/core/router/transports/ssu/server.cc b/src/core/router/transports/ssu/server.cc index fa06b4d1..318dc47e 100644 --- a/src/core/router/transports/ssu/server.cc +++ b/src/core/router/transports/ssu/server.cc @@ -375,7 +375,7 @@ std::shared_ptr SSUServer::GetSession( << introducer->host << ":" << introducer->port; session->WaitForIntroduction(); // if we are unreachable - if (kovri::context.GetRouterInfo().UsesIntroducer()) { + if (context.GetRouterInfo().UsesIntroducer()) { std::array buf {{}}; Send(buf.data(), 0, remote_endpoint); // send HolePunch } @@ -483,15 +483,15 @@ void SSUServer::HandleIntroducersUpdateTimer( LOG(debug) << "SSUServer: handling introducers update timer"; if (ecode != boost::asio::error::operation_aborted) { // timeout expired - if (kovri::context.GetStatus() == eRouterStatusTesting) { + if (context.GetStatus() == eRouterStatusTesting) { // we still don't know if we need introducers ScheduleIntroducersUpdateTimer(); return; } - if (kovri::context.GetStatus () == eRouterStatusOK) + if (context.GetStatus () == eRouterStatusOK) return; // we don't need introducers anymore // we are firewalled - if (!kovri::context.IsUnreachable()) kovri::context.SetUnreachable(); + if (!context.IsUnreachable()) context.SetUnreachable(); std::list new_list; std::size_t num_introducers = 0; std::uint32_t ts = kovri::core::GetSecondsSinceEpoch(); // Timestamp @@ -504,7 +504,7 @@ void SSUServer::HandleIntroducersUpdateTimer( new_list.push_back(introducer); num_introducers++; } else { - kovri::context.RemoveIntroducer(introducer); + context.RemoveIntroducer(introducer); } } auto max_introducers = GetType(SSUSize::MaxIntroducers); @@ -515,7 +515,7 @@ void SSUServer::HandleIntroducersUpdateTimer( for (auto it : introducers) { auto router = it->GetRemoteRouter(); if (router && - kovri::context.AddIntroducer(*router, it->GetRelayTag())) { + context.AddIntroducer(*router, it->GetRelayTag())) { new_list.push_back(it->GetRemoteEndpoint()); if (new_list.size() >= max_introducers) break; diff --git a/src/core/router/transports/ssu/session.cc b/src/core/router/transports/ssu/session.cc index 2d440c4b..fa4e1e9e 100644 --- a/src/core/router/transports/ssu/session.cc +++ b/src/core/router/transports/ssu/session.cc @@ -196,7 +196,7 @@ void SSUSession::ProcessNextMessage( if (!validated) { // try own intro key - auto address = kovri::context.GetRouterInfo().GetSSUAddress(); + auto address = context.GetRouterInfo().GetSSUAddress(); if (!address) { LOG(error) << "SSUSession: " << __func__ @@ -342,7 +342,7 @@ void SSUSession::SendSessionRequest() { packet.SetDhX(m_DHKeysPair->public_key.data()); // Fill extended options std::array extended_data {{ 0x00, 0x00 }}; - if (kovri::context.GetStatus() == eRouterStatusOK) { // we don't need relays + if (context.GetStatus() == eRouterStatusOK) { // we don't need relays packet.GetHeader()->SetExtendedOptions(true); packet.GetHeader()->SetExtendedOptionsData(extended_data.data(), 2); } @@ -401,7 +401,7 @@ void SSUSession::ProcessSessionCreated( << "SSUSession:" << GetFormattedSessionInfo() << __func__ << ": our external address is " << our_IP.to_string() << ":" << packet->GetPort(); - kovri::context.UpdateAddress(our_IP); + context.UpdateAddress(our_IP); if (GetRemoteEndpoint().address().is_v4()) { // remote IP v4 s.Insert(GetRemoteEndpoint().address().to_v4().to_bytes().data(), 4); @@ -451,8 +451,8 @@ void SSUSession::SendSessionCreated( const std::uint8_t* x) { auto intro_key = GetIntroKey(); auto address = IsV6() ? - kovri::context.GetRouterInfo().GetSSUAddress(true) : - kovri::context.GetRouterInfo().GetSSUAddress(); // v4 only + context.GetRouterInfo().GetSSUAddress(true) : + context.GetRouterInfo().GetSSUAddress(); // v4 only if (!intro_key || !address) { LOG(error) << "SSUSession:" << GetFormattedSessionInfo() @@ -482,7 +482,7 @@ void SSUSession::SendSessionCreated( s.Insert (htobe16(address->port)); // our port std::uint32_t relay_tag = 0; - if (kovri::context.GetRouterInfo().HasCap(RouterInfo::Cap::SSUIntroducer)) { + if (context.GetRouterInfo().HasCap(RouterInfo::Cap::SSUIntroducer)) { relay_tag = kovri::core::Rand(); if (!relay_tag) relay_tag = 1; @@ -496,14 +496,14 @@ void SSUSession::SendSessionCreated( m_SessionConfirmData = std::make_unique(s); // Set signature size to compute the required padding size - std::size_t signature_size = kovri::context.GetIdentity().GetSignatureLen(); + std::size_t signature_size = context.GetIdentity().GetSignatureLen(); packet.SetSignature(nullptr, signature_size); const std::size_t sig_padding = SSUPacketBuilder::GetPaddingSize( packet.GetSize()); // Set signature with correct size and fill the padding auto signature_buf = std::make_unique( signature_size + sig_padding); - s.Sign(kovri::context.GetPrivateKeys(), signature_buf.get()); + s.Sign(context.GetPrivateKeys(), signature_buf.get()); kovri::core::RandBytes(signature_buf.get() + signature_size, sig_padding); packet.SetSignature(signature_buf.get(), signature_size + sig_padding); @@ -571,10 +571,10 @@ void SSUSession::SendSessionConfirmed( std::array iv; kovri::core::RandBytes(iv.data(), iv.size()); packet.GetHeader()->SetIV(iv.data()); - packet.SetRemoteRouterIdentity(kovri::context.GetIdentity()); + packet.SetRemoteRouterIdentity(context.GetIdentity()); packet.SetSignedOnTime(kovri::core::GetSecondsSinceEpoch()); auto signature_buf = std::make_unique( - kovri::context.GetIdentity().GetSignatureLen()); + context.GetIdentity().GetSignatureLen()); // signature // x,y, our IP, our port, remote IP, remote port, // relay_tag, our signed on time @@ -591,7 +591,7 @@ void SSUSession::SendSessionConfirmed( s.Insert(htobe16(GetRemoteEndpoint().port())); // remote port s.Insert(htobe32(m_RelayTag)); s.Insert(htobe32(packet.GetSignedOnTime())); - s.Sign(kovri::context.GetPrivateKeys(), signature_buf.get()); + s.Sign(context.GetPrivateKeys(), signature_buf.get()); packet.SetSignature(signature_buf.get()); const std::size_t packet_size = SSUPacketBuilder::GetPaddedSize(packet.GetSize()); const std::size_t buffer_size = packet_size + GetType(SSUSize::BufferMargin); @@ -624,7 +624,7 @@ void SSUSession::ProcessRelayRequest( void SSUSession::SendRelayRequest( std::uint32_t introducer_tag, const std::uint8_t* introducer_key) { - auto address = kovri::context.GetRouterInfo().GetSSUAddress(); + auto address = context.GetRouterInfo().GetSSUAddress(); if (!address) { LOG(error) << "SSUSession:" << GetFormattedSessionInfo() @@ -696,7 +696,7 @@ void SSUSession::ProcessRelayResponse(SSUPacket* pkt) { << "SSUSession:" << GetFormattedSessionInfo() << __func__ << ": our external address is " << our_IP.to_string() << ":" << packet->GetPortAlice(); - kovri::context.UpdateAddress(our_IP); + context.UpdateAddress(our_IP); } void SSUSession::SendRelayResponse( @@ -873,13 +873,13 @@ void SSUSession::ProcessPeerTest( LOG(debug) << "SSUSession:" << GetFormattedSessionInfo() << "PeerTest from Bob. We are Alice"; - if (kovri::context.GetStatus() == eRouterStatusTesting) // still not OK - kovri::context.SetStatus(eRouterStatusFirewalled); + if (context.GetStatus() == eRouterStatusTesting) // still not OK + context.SetStatus(eRouterStatusFirewalled); } else { LOG(debug) << "SSUSession:" << GetFormattedSessionInfo() << "first PeerTest from Charlie. We are Alice"; - kovri::context.SetStatus(eRouterStatusOK); + context.SetStatus(eRouterStatusOK); m_Server.UpdatePeerTest( packet->GetNonce(), PeerTestParticipant::Alice2); @@ -903,7 +903,7 @@ void SSUSession::ProcessPeerTest( LOG(debug) << "SSUSession:" << GetFormattedSessionInfo() << "second PeerTest from Charlie. We are Alice"; - kovri::context.SetStatus(eRouterStatusOK); + context.SetStatus(eRouterStatusOK); m_Server.RemovePeerTest(packet->GetNonce()); } break; @@ -1005,7 +1005,7 @@ void SSUSession::SendPeerTest( // intro key if (to_address) { // send our intro key to address instead it's own - auto addr = kovri::context.GetRouterInfo().GetSSUAddress(); + auto addr = context.GetRouterInfo().GetSSUAddress(); if (addr) memcpy(payload, addr->key, 32); // intro key else @@ -1045,7 +1045,7 @@ void SSUSession::SendPeerTest( void SSUSession::SendPeerTest() { // we are Alice LOG(debug) << "SSUSession: <--" << GetFormattedSessionInfo() << "sending PeerTest"; - auto address = kovri::context.GetRouterInfo().GetSSUAddress(); + auto address = context.GetRouterInfo().GetSSUAddress(); if (!address) { LOG(error) << "SSUSession:" << GetFormattedSessionInfo() @@ -1457,7 +1457,7 @@ const std::uint8_t* SSUSession::GetIntroKey() const { return address ? (const std::uint8_t *)address->key : nullptr; } else { // we are server - auto address = kovri::context.GetRouterInfo().GetSSUAddress(); + auto address = context.GetRouterInfo().GetSSUAddress(); return address ? (const std::uint8_t *)address->key : nullptr; } } diff --git a/src/core/router/transports/upnp.cc b/src/core/router/transports/upnp.cc index ec9f8d68..13d83147 100644 --- a/src/core/router/transports/upnp.cc +++ b/src/core/router/transports/upnp.cc @@ -252,7 +252,7 @@ void UPnP::Discover() { } else { if (m_externalIPAddress[0]) { LOG(debug) << "UPnP: external IP address: " << m_externalIPAddress; - kovri::context.UpdateAddress( + context.UpdateAddress( boost::asio::ip::address::from_string( m_externalIPAddress)); return; diff --git a/src/core/router/tunnel/config.cc b/src/core/router/tunnel/config.cc index 8593d9fe..7c8d557c 100644 --- a/src/core/router/tunnel/config.cc +++ b/src/core/router/tunnel/config.cc @@ -254,7 +254,7 @@ TunnelConfig::TunnelConfig( m_FirstHop->SetIsGateway(false); m_LastHop->SetReplyHop(reply_tunnel_config->GetFirstHop()); } else { // inbound - m_LastHop->SetNextRouter(kovri::context.GetSharedRouterInfo()); + m_LastHop->SetNextRouter(context.GetSharedRouterInfo()); } } } diff --git a/src/core/router/tunnel/endpoint.cc b/src/core/router/tunnel/endpoint.cc index 06ef143b..558381a0 100644 --- a/src/core/router/tunnel/endpoint.cc +++ b/src/core/router/tunnel/endpoint.cc @@ -302,7 +302,7 @@ void TunnelEndpoint::HandleNextMessage( break; case e_DeliveryTypeRouter: // check if message is sent to us - if (msg.hash == kovri::context.GetRouterInfo().GetIdentHash()) { + if (msg.hash == context.GetRouterInfo().GetIdentHash()) { kovri::core::HandleI2NPMessage(msg.data); } else { // to somebody else diff --git a/src/core/router/tunnel/impl.cc b/src/core/router/tunnel/impl.cc index 4d3ee2bc..9998a3fd 100644 --- a/src/core/router/tunnel/impl.cc +++ b/src/core/router/tunnel/impl.cc @@ -651,7 +651,7 @@ void Tunnels::ManageInboundTunnels() { if (!m_ExploratoryPool) m_ExploratoryPool = // 2-hop exploratory, 5 tunnels - CreateTunnelPool(&kovri::context, 2, 2, 5, 5); + CreateTunnelPool(&context, 2, 2, 5, 5); return; } if (m_OutboundTunnels.empty() || m_InboundTunnels.size() < 5) { @@ -756,7 +756,7 @@ void Tunnels::CreateZeroHopsInboundTunnel() { CreateTunnel ( std::make_shared ( std::vector > { - kovri::context.GetSharedRouterInfo() + context.GetSharedRouterInfo() })); } diff --git a/src/core/router/tunnel/pool.cc b/src/core/router/tunnel/pool.cc index cc474e59..6fe7bf69 100644 --- a/src/core/router/tunnel/pool.cc +++ b/src/core/router/tunnel/pool.cc @@ -331,7 +331,7 @@ void TunnelPool::ProcessDeliveryStatus( std::shared_ptr TunnelPool::SelectNextHop( std::shared_ptr prev_hop) const { // TODO(unassigned): implement it better - bool is_exploratory = (m_LocalDestination == &kovri::context); + bool is_exploratory = (m_LocalDestination == &context); auto hop = is_exploratory ? kovri::core::netdb.GetRandomRouter(prev_hop) : kovri::core::netdb.GetHighBandwidthRandomRouter(prev_hop); @@ -345,7 +345,7 @@ bool TunnelPool::SelectPeers( bool is_inbound) { if (m_ExplicitPeers) return SelectExplicitPeers(hops, is_inbound); - auto prev_hop = kovri::context.GetSharedRouterInfo(); + auto prev_hop = context.GetSharedRouterInfo(); int num_hops = is_inbound ? m_NumInboundHops : m_NumOutboundHops; From 55df5b9c7616585cb753908cbf0ffe2e4c6eb110 Mon Sep 17 00:00:00 2001 From: anonimal Date: Wed, 15 Nov 2017 03:40:25 +0000 Subject: [PATCH 02/10] Core: initial rewrite of router initialization Also adds new filesystem util function. --- src/core/instance.cc | 41 +-------- src/core/router/context.cc | 170 ++++++++++++++++++++++--------------- src/core/router/context.h | 14 +-- src/core/router/info.h | 1 + src/core/util/filesystem.h | 20 +++++ 5 files changed, 130 insertions(+), 116 deletions(-) diff --git a/src/core/instance.cc b/src/core/instance.cc index 8f31e1da..8c2a7692 100644 --- a/src/core/instance.cc +++ b/src/core/instance.cc @@ -82,46 +82,9 @@ Instance::~Instance() {} // Note: we'd love Instance RAII but singleton needs to be daemonized (if applicable) before initialization void Instance::Initialize() { - // TODO(unassigned): see TODO's for router context and singleton LOG(debug) << "Instance: initializing core"; - auto const& map = m_Config.GetMap(); - auto host = map["host"].as(); - - // Random generated port if none is supplied via CLI or config - // See: i2p.i2p/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java - auto const port = - map["port"].defaulted() - ? RandInRange32(RouterInfo::MinPort, RouterInfo::MaxPort) - : map["port"].as(); - LOG(info) << "Instance: listening on port " << port; - - context.Init(host, port); - context.UpdatePort(port); - - context.UpdateAddress(boost::asio::ip::address::from_string(host)); - context.SetSupportsV6(map["v6"].as()); - context.SetFloodfill(map["floodfill"].as()); - - auto const bandwidth = map["bandwidth"].as(); - if (!bandwidth.empty()) - { - if (bandwidth[0] > 'L') - context.SetHighBandwidth(); - else - context.SetLowBandwidth(); - } - - // Set reseed options - context.SetOptionReseedFrom(map["reseed-from"].as()); - context.SetOptionDisableSU3Verification( - map["disable-su3-verification"].as()); - - // Set transport options - context.SetSupportsNTCP(map["enable-ntcp"].as()); - context.SetSupportsSSU(map["enable-ssu"].as()); - - // Set SSL option - context.SetOptionEnableSSL(map["enable-ssl"].as()); + // TODO(unassigned): see TODOs for router context and singleton + context.Initialize(m_Config.GetMap()); } void Instance::Start() diff --git a/src/core/router/context.cc b/src/core/router/context.cc index 59854776..d8ee082e 100644 --- a/src/core/router/context.cc +++ b/src/core/router/context.cc @@ -33,6 +33,7 @@ #include "core/router/context.h" #include +#include #include @@ -65,43 +66,110 @@ RouterContext::RouterContext() m_SupportsNTCP(true), m_SupportsSSU(true) {} -void RouterContext::Init( - const std::string& host, - std::uint16_t port) { - m_Host = host; - m_Port = port; - m_StartupTime = kovri::core::GetSecondsSinceEpoch(); - if (!Load()) - CreateNewRouter(); +// TODO(anonimal): review context's RI initialization options +void RouterContext::Initialize(const boost::program_options::variables_map& map) +{ + m_StartupTime = core::GetSecondsSinceEpoch(); + m_Host = map["host"].as(); + m_Port = map["port"].defaulted() + ? RandInRange32(RouterInfo::MinPort, RouterInfo::MaxPort) + : map["port"].as(); + + // Set paths + auto path = core::EnsurePath(core::GetCorePath()); + auto keys_path = (path / ROUTER_KEYS).string(); + auto info_path = (path / ROUTER_INFO).string(); + + // Load keys for RI creation + LOG(debug) << "RouterContext: attempting to use keys " << keys_path; + core::InputFileStream keys(keys_path, std::ifstream::binary); + + // If key does not exist, create - then create RI + if (keys.Fail()) + { + LOG(debug) << "RouterContext: creating router keys"; + m_Keys = core::PrivateKeys::CreateRandomKeys( + core::DEFAULT_ROUTER_SIGNING_KEY_TYPE); + + LOG(debug) << "RouterContext: writing router keys"; + core::OutputFileStream keys(keys_path, std::ofstream::binary); + std::vector buf(m_Keys.GetFullLen()); + m_Keys.ToBuffer(buf.data(), buf.size()); + keys.Write(buf.data(), buf.size()); + + LOG(debug) << "RouterContext: preparing RI creation"; + core::RouterInfo router; + + router.SetRouterIdentity(GetIdentity()); + router.AddSSUAddress(m_Host, m_Port, router.GetIdentHash()); + router.AddNTCPAddress(m_Host, m_Port); + router.SetCaps( + core::RouterInfo::Cap::Reachable + // TODO(anonimal): but what if we've disabled run-time SSU... + | core::RouterInfo::Cap::SSUTesting + | core::RouterInfo::Cap::SSUIntroducer); + router.SetOption("netId", std::to_string(I2P_NETWORK_ID)); + router.SetOption("router.version", I2P_VERSION); + + LOG(debug) << "RouterContext: creating RI from in-memory keys"; + router.CreateBuffer(m_Keys); + m_RouterInfo.Update(router.GetBuffer(), router.GetBufferLen()); + } + else + { + LOG(debug) << "RouterContext: reading existing keys into memory"; + std::vector buf = keys.ReadAll(); + // Note: over/underflow checks done in callee + m_Keys.FromBuffer(buf.data(), buf.size()); + + LOG(debug) << "RouterContext: updating existing RI " << info_path; + core::RouterInfo router(info_path); + + m_RouterInfo.Update(router.GetBuffer(), router.GetBufferLen()); + m_RouterInfo.SetOption("coreVersion", I2P_VERSION); + m_RouterInfo.SetOption("router.version", I2P_VERSION); + + if (IsUnreachable()) + // we assume reachable until we discover firewall through peer tests + SetReachable(); + } + + // TODO(anonimal): logically speaking, this should be called *after* updating + // address and port (though this is called within those functions) UpdateRouterInfo(); -} -void RouterContext::CreateNewRouter() { - m_Keys = kovri::core::PrivateKeys::CreateRandomKeys( - kovri::core::DEFAULT_ROUTER_SIGNING_KEY_TYPE); - SaveKeys(); - NewRouterInfo(); -} + // TODO(anonimal): micro-managing RI traits on a per-function basis feels like an anti-pattern + UpdateAddress(boost::asio::ip::address::from_string(m_Host)); + UpdatePort(m_Port); + + // TODO(anonimal): rewrite all core context setters + + SetSupportsV6(map["v6"].as()); + SetFloodfill(map["floodfill"].as()); -void RouterContext::NewRouterInfo() { - kovri::core::RouterInfo routerInfo; - routerInfo.SetRouterIdentity( - GetIdentity()); - routerInfo.AddSSUAddress(m_Host, m_Port, routerInfo.GetIdentHash()); - routerInfo.AddNTCPAddress(m_Host, m_Port); - routerInfo.SetCaps( - core::RouterInfo::Cap::Reachable | - core::RouterInfo::Cap::SSUTesting | // TODO(anonimal): if we've disabled run-time SSU... - core::RouterInfo::Cap::SSUIntroducer); - routerInfo.SetOption("netId", std::to_string(I2P_NETWORK_ID)); - routerInfo.SetOption("router.version", I2P_VERSION); - routerInfo.CreateBuffer(m_Keys); - m_RouterInfo.Update( - routerInfo.GetBuffer(), - routerInfo.GetBufferLen()); + auto const bandwidth = map["bandwidth"].as(); + if (!bandwidth.empty()) + { + if (bandwidth[0] > 'L') + SetHighBandwidth(); + else + SetLowBandwidth(); + } + + // Set reseed options + SetOptionReseedFrom(map["reseed-from"].as()); + SetOptionDisableSU3Verification(map["disable-su3-verification"].as()); + + // Set transport options + SetSupportsNTCP(map["enable-ntcp"].as()); + SetSupportsSSU(map["enable-ssu"].as()); + + // Set SSL option + SetOptionEnableSSL(map["enable-ssl"].as()); } void RouterContext::UpdateRouterInfo() { + LOG(debug) << "RouterContext: updating RI, saving to file"; m_RouterInfo.CreateBuffer(m_Keys); m_RouterInfo.SaveToFile((kovri::core::GetCorePath() / ROUTER_INFO).string()); m_LastUpdateTime = kovri::core::GetSecondsSinceEpoch(); @@ -117,7 +185,10 @@ void RouterContext::UpdatePort( } } if (updated) - UpdateRouterInfo(); + { + LOG(info) << "RouterContext: listening on port " << m_Port; + UpdateRouterInfo(); + } } void RouterContext::UpdateAddress( @@ -309,41 +380,6 @@ void RouterContext::UpdateStats() { } } -bool RouterContext::Load() { - auto path = kovri::core::EnsurePath(kovri::core::GetCorePath()); - std::ifstream fk((path / ROUTER_KEYS).string(), std::ifstream::binary); - // If key does not exist, create - if (!fk.is_open()) - return false; - fk.seekg(0, std::ios::end); - const std::size_t len = fk.tellg(); - fk.seekg(0, std::ios::beg); - std::unique_ptr buf(std::make_unique(len)); - fk.read(reinterpret_cast(buf.get()), len); - m_Keys.FromBuffer(buf.get(), len); - kovri::core::RouterInfo router_info( - (kovri::core::GetCorePath() / ROUTER_INFO).string()); - m_RouterInfo.Update( - router_info.GetBuffer(), - router_info.GetBufferLen()); - m_RouterInfo.SetOption("coreVersion", I2P_VERSION); - m_RouterInfo.SetOption("router.version", I2P_VERSION); - if (IsUnreachable()) - // we assume reachable until we discover firewall through peer tests - SetReachable(); - return true; -} - -void RouterContext::SaveKeys() { - std::ofstream fk( - (kovri::core::GetCorePath() / ROUTER_KEYS).string(), - std::ofstream::binary); - const std::size_t len = m_Keys.GetFullLen(); - std::unique_ptr buf(std::make_unique(len)); - m_Keys.ToBuffer(buf.get(), len); - fk.write(reinterpret_cast(buf.get()), len); -} - void RouterContext::RemoveTransport( core::RouterInfo::Transport transport) { auto& addresses = m_RouterInfo.GetAddresses(); diff --git a/src/core/router/context.h b/src/core/router/context.h index a24587d3..ea98293e 100644 --- a/src/core/router/context.h +++ b/src/core/router/context.h @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -67,12 +68,9 @@ class RouterContext : public kovri::core::GarlicDestination { public: RouterContext(); - /// Initializes the router context, must be called before use - /// @param host The external address of this router - /// @param port The external port of this router - void Init( - const std::string& host, - std::uint16_t port); + /// @brief Initializes the router context, must be called before further context use + /// @param map Variable map used to initialize context options + void Initialize(const boost::program_options::variables_map& map); // @return This RouterContext's RouterInfo kovri::core::RouterInfo& GetRouterInfo() { @@ -311,11 +309,7 @@ class RouterContext : public kovri::core::GarlicDestination { } private: - void CreateNewRouter(); - void NewRouterInfo(); void UpdateRouterInfo(); - bool Load(); - void SaveKeys(); void RemoveTransport(core::RouterInfo::Transport transport); private: diff --git a/src/core/router/info.h b/src/core/router/info.h index eae33853..9cb61b60 100644 --- a/src/core/router/info.h +++ b/src/core/router/info.h @@ -69,6 +69,7 @@ struct RouterInfoTraits /// @enum PortRange /// @brief Min and Max public port + /// @note See i2p.i2p/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java enum PortRange : std::uint16_t { MinPort = 9111, diff --git a/src/core/util/filesystem.h b/src/core/util/filesystem.h index 4b5bfeaf..aee17c45 100644 --- a/src/core/util/filesystem.h +++ b/src/core/util/filesystem.h @@ -204,6 +204,26 @@ class FileStream { return buf; } + std::vector ReadAll() + { + Seekg(0, std::ios::end); + if (Fail()) + throw std::runtime_error("FileStream: input does not support seekg"); + + const auto len = Tellg(); + LOG(trace) << "FileStream: input length " << len; + if (!len) + throw std::runtime_error("FileStream: empty input"); + + Seekg(0, std::ios::beg); + + std::vector buf(len); + if (!Read(buf.data(), buf.size())) + throw std::runtime_error("FileStream: Failed to read input"); + + return buf; + } + /// @brief Write to stream /// @param buf : buffer to write to /// @param size : number of byte to write From 32b9d7cac1935a69dbc7df401171a303ec556e2e Mon Sep 17 00:00:00 2001 From: anonimal Date: Thu, 16 Nov 2017 05:16:24 +0000 Subject: [PATCH 03/10] Core: WIP rewrite of router initialization and many TODOs. --- src/client/reseed.cc | 7 +- src/client/reseed.h | 18 +++- src/client/util/http.cc | 2 +- src/core/router/context.cc | 212 ++++++++++++++++--------------------- src/core/router/context.h | 96 ++--------------- src/core/util/config.cc | 4 +- 6 files changed, 123 insertions(+), 216 deletions(-) diff --git a/src/client/reseed.cc b/src/client/reseed.cc index 4a7e9434..0d90fe35 100644 --- a/src/client/reseed.cc +++ b/src/client/reseed.cc @@ -88,7 +88,10 @@ bool Reseed::Start() { } } // Implement SU3 - SU3 su3(m_Stream, m_SigningKeys); + SU3 su3( + m_Stream, + m_SigningKeys, + core::context.GetOpts()["disable-su3-verification"].as()); if (!su3.SU3Impl()) { LOG(error) << "Reseed: SU3 implementation failed"; return false; @@ -239,7 +242,7 @@ bool Reseed::FetchStream( */ bool SU3::SU3Impl() { - if (core::context.GetOptionDisableSU3Verification()) + if (m_DisableVerification) { LOG(warning) << "SU3: verification disabled !"; // TODO(unassigned): detection and implemention of other formats diff --git a/src/client/reseed.h b/src/client/reseed.h index dc9c4e8f..64119aa6 100644 --- a/src/client/reseed.h +++ b/src/client/reseed.h @@ -69,8 +69,11 @@ class Reseed { public: /// @brief Constructs stream from string explicit Reseed( - const std::string& stream = core::context.GetOptionReseedFrom()) - : m_Stream(stream) {} + const std::string& stream = + core::context.GetOpts()["reseed-from"].as()) + : m_Stream(stream) + { + } /// @brief Reseed implementation /// @details Oversees fetching and processing of SU3 @@ -136,14 +139,18 @@ class Reseed { /** * @class SU3 * @brief SU3 implementation - * @param String of bytes that *must* be an SU3 + * @param su3 String of bytes that *must* be an SU3 + * @param keys Pubkeys to verify with + * @param disable_verification Disable signed SU3 verification? */ class SU3 { public: SU3(const std::string& su3, - std::map& keys) + std::map& keys, + bool disable_verification = false) : m_Stream(su3), m_SigningKeys(keys), + m_DisableVerification(disable_verification), m_Data(std::make_unique()) {} // Extracted RI's (map of router info files) @@ -276,6 +283,9 @@ class SU3 { // X.509 signing keys for SU3 verification std::map m_SigningKeys; + /// @brief Disable SU3 verification? + bool m_DisableVerification; + // Spec-defined data std::unique_ptr m_Data; }; diff --git a/src/client/util/http.cc b/src/client/util/http.cc index b501697b..ad498525 100644 --- a/src/client/util/http.cc +++ b/src/client/util/http.cc @@ -117,7 +117,7 @@ bool HTTP::DownloadViaClearnet() { LOG(debug) << "HTTP: Download Clearnet with timeout : " << kovri::core::GetType(Timeout::Request); // Ensure that we only download from explicit SSL-enabled hosts - if (core::context.GetOptionEnableSSL()) { + if (core::context.GetOpts()["enable-ssl"].as()) { const std::string cert = uri.host() + ".crt"; const boost::filesystem::path cert_path = kovri::core::GetSSLCertsPath() / cert; if (!boost::filesystem::exists(cert_path)) { diff --git a/src/core/router/context.cc b/src/core/router/context.cc index d8ee082e..a8a897ff 100644 --- a/src/core/router/context.cc +++ b/src/core/router/context.cc @@ -57,29 +57,30 @@ RouterContext context; RouterContext::RouterContext() : m_LastUpdateTime(0), m_AcceptsTunnels(true), - m_IsFloodfill(false), m_StartupTime(0), - m_Status(eRouterStatusOK), - m_Port(0), - m_EnableSSL(true), - m_DisableSU3Verification(false), - m_SupportsNTCP(true), - m_SupportsSSU(true) {} + m_Status(eRouterStatusOK) {} // TODO(anonimal): review context's RI initialization options +// TODO(anonimal): determine which functions are truly context and which are RI void RouterContext::Initialize(const boost::program_options::variables_map& map) { - m_StartupTime = core::GetSecondsSinceEpoch(); - m_Host = map["host"].as(); - m_Port = map["port"].defaulted() - ? RandInRange32(RouterInfo::MinPort, RouterInfo::MaxPort) - : map["port"].as(); + // TODO(anonimal): we want context ctor initialization with non-bpo object + m_Opts = map; // Set paths auto path = core::EnsurePath(core::GetCorePath()); auto keys_path = (path / ROUTER_KEYS).string(); auto info_path = (path / ROUTER_INFO).string(); + // Set host/port for RI creation/updating + auto host = m_Opts["host"].as(); // TODO(anonimal): fix default host + auto port = m_Opts["port"].defaulted() + ? RandInRange32(RouterInfo::MinPort, RouterInfo::MaxPort) + : m_Opts["port"].as(); + + // Set startup time + m_StartupTime = core::GetSecondsSinceEpoch(); + // Load keys for RI creation LOG(debug) << "RouterContext: attempting to use keys " << keys_path; core::InputFileStream keys(keys_path, std::ifstream::binary); @@ -101,13 +102,15 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) core::RouterInfo router; router.SetRouterIdentity(GetIdentity()); - router.AddSSUAddress(m_Host, m_Port, router.GetIdentHash()); - router.AddNTCPAddress(m_Host, m_Port); + router.AddSSUAddress(host, port, router.GetIdentHash()); + router.AddNTCPAddress(host, port); router.SetCaps( core::RouterInfo::Cap::Reachable // TODO(anonimal): but what if we've disabled run-time SSU... | core::RouterInfo::Cap::SSUTesting | core::RouterInfo::Cap::SSUIntroducer); + + // Set options router.SetOption("netId", std::to_string(I2P_NETWORK_ID)); router.SetOption("router.version", I2P_VERSION); @@ -115,7 +118,7 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) router.CreateBuffer(m_Keys); m_RouterInfo.Update(router.GetBuffer(), router.GetBufferLen()); } - else + else // Keys (and RI should also) exist { LOG(debug) << "RouterContext: reading existing keys into memory"; std::vector buf = keys.ReadAll(); @@ -125,47 +128,93 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) LOG(debug) << "RouterContext: updating existing RI " << info_path; core::RouterInfo router(info_path); + // Update address/port + const auto address = boost::asio::ip::address::from_string(host); + for (auto& router : m_RouterInfo.GetAddresses()) + { + if (router.host != address && router.HasCompatibleHost(address)) + router.host = address; + if (router.port != port) + router.port = port; + } + + // Set RI options + router.SetOption("coreVersion", I2P_VERSION); + router.SetOption("router.version", I2P_VERSION); + + // Update context RI m_RouterInfo.Update(router.GetBuffer(), router.GetBufferLen()); - m_RouterInfo.SetOption("coreVersion", I2P_VERSION); - m_RouterInfo.SetOption("router.version", I2P_VERSION); + // Test for reachability of context's RI if (IsUnreachable()) // we assume reachable until we discover firewall through peer tests SetReachable(); } - // TODO(anonimal): logically speaking, this should be called *after* updating - // address and port (though this is called within those functions) - UpdateRouterInfo(); + LOG(info) << "RouterContext: will listen on host " << host; + LOG(info) << "RouterContext: will listen on port " << port; - // TODO(anonimal): micro-managing RI traits on a per-function basis feels like an anti-pattern - UpdateAddress(boost::asio::ip::address::from_string(m_Host)); - UpdatePort(m_Port); + // TODO(anonimal): we don't want a flurry of micro-managed setter functions + // but we also don't want to re-initialize context just to update certain RI + // traits! Note: updating RI traits doesn't update server sockets + LOG(debug) << "RouterContext: setting context RI traits"; - // TODO(anonimal): rewrite all core context setters + // IPv6 + m_Opts["v6"].as() ? m_RouterInfo.EnableV6() : m_RouterInfo.DisableV6(); - SetSupportsV6(map["v6"].as()); - SetFloodfill(map["floodfill"].as()); + // Floodfill + if (m_Opts["floodfill"].as()) + { + m_RouterInfo.SetCaps( + m_RouterInfo.GetCaps() | core::RouterInfo::Cap::Floodfill); + } + else + { + m_RouterInfo.SetCaps( + m_RouterInfo.GetCaps() & ~core::RouterInfo::Cap::Floodfill); + // we don't publish number of routers and leaseset for non-floodfill + m_RouterInfo.GetOptions().erase(ROUTER_INFO_OPTION_LEASESETS); + m_RouterInfo.GetOptions().erase(ROUTER_INFO_OPTION_ROUTERS); + } - auto const bandwidth = map["bandwidth"].as(); + // Bandcaps + auto const bandwidth = m_Opts["bandwidth"].as(); if (!bandwidth.empty()) { - if (bandwidth[0] > 'L') - SetHighBandwidth(); + auto const cap = core::RouterInfo::Cap::HighBandwidth; + if (bandwidth[0] > 'L') // TODO(anonimal): refine + { + if (!m_RouterInfo.HasCap(cap)) + m_RouterInfo.SetCaps(m_RouterInfo.GetCaps() | cap); + } else - SetLowBandwidth(); + { + if (m_RouterInfo.HasCap(cap)) + m_RouterInfo.SetCaps(m_RouterInfo.GetCaps() & ~cap); + } } - // Set reseed options - SetOptionReseedFrom(map["reseed-from"].as()); - SetOptionDisableSU3Verification(map["disable-su3-verification"].as()); + // NTCP + bool ntcp = m_Opts["enable-ntcp"].as(); + if (ntcp && !m_RouterInfo.GetNTCPAddress()) + m_RouterInfo.AddNTCPAddress(host, port); + if (!ntcp) + RemoveTransport(core::RouterInfo::Transport::NTCP); - // Set transport options - SetSupportsNTCP(map["enable-ntcp"].as()); - SetSupportsSSU(map["enable-ssu"].as()); + // SSU + bool ssu = m_Opts["enable-ssu"].as(); + if (ssu && !m_RouterInfo.GetSSUAddress()) + m_RouterInfo.AddSSUAddress(host, port, m_RouterInfo.GetIdentHash()); + if (!ssu) + RemoveTransport(core::RouterInfo::Transport::SSU); - // Set SSL option - SetOptionEnableSSL(map["enable-ssl"].as()); + // Remove SSU-related flags + m_RouterInfo.SetCaps( + m_RouterInfo.GetCaps() & ~core::RouterInfo::Cap::SSUTesting + & ~core::RouterInfo::Cap::SSUIntroducer); + + // Update RI/commit to disk + UpdateRouterInfo(); } void RouterContext::UpdateRouterInfo() { @@ -175,22 +224,6 @@ void RouterContext::UpdateRouterInfo() { m_LastUpdateTime = kovri::core::GetSecondsSinceEpoch(); } -void RouterContext::UpdatePort( - std::uint16_t port) { - bool updated = false; - for (auto& address : m_RouterInfo.GetAddresses()) { - if (address.port != port) { - address.port = port; - updated = true; - } - } - if (updated) - { - LOG(info) << "RouterContext: listening on port " << m_Port; - UpdateRouterInfo(); - } -} - void RouterContext::UpdateAddress( const boost::asio::ip::address& host) { bool updated = false; @@ -224,38 +257,6 @@ void RouterContext::RemoveIntroducer( UpdateRouterInfo(); } -void RouterContext::SetFloodfill( - bool floodfill) { - m_IsFloodfill = floodfill; - if (floodfill) { - m_RouterInfo.SetCaps( - m_RouterInfo.GetCaps() | core::RouterInfo::Cap::Floodfill); - } else { - m_RouterInfo.SetCaps( - m_RouterInfo.GetCaps() & ~core::RouterInfo::Cap::Floodfill); - // we don't publish number of routers and leaseset for non-floodfill - m_RouterInfo.GetOptions().erase(ROUTER_INFO_OPTION_LEASESETS); - m_RouterInfo.GetOptions().erase(ROUTER_INFO_OPTION_ROUTERS); - } - UpdateRouterInfo(); -} - -void RouterContext::SetHighBandwidth() { - auto cap = core::RouterInfo::Cap::HighBandwidth; - if (!m_RouterInfo.HasCap(cap)) { - m_RouterInfo.SetCaps(m_RouterInfo.GetCaps() | cap); - UpdateRouterInfo(); - } -} - -void RouterContext::SetLowBandwidth() { - auto cap = core::RouterInfo::Cap::HighBandwidth; - if (m_RouterInfo.HasCap(cap)) { - m_RouterInfo.SetCaps(m_RouterInfo.GetCaps() & ~cap); - UpdateRouterInfo(); - } -} - bool RouterContext::IsUnreachable() const { return m_RouterInfo.GetCaps() & core::RouterInfo::Cap::Unreachable; } @@ -279,7 +280,7 @@ void RouterContext::SetReachable() { caps &= ~core::RouterInfo::Cap::Unreachable; caps |= core::RouterInfo::Cap::Reachable; caps |= core::RouterInfo::Cap::SSUIntroducer; - if (m_IsFloodfill) + if (IsFloodfill()) caps |= core::RouterInfo::Cap::Floodfill; m_RouterInfo.SetCaps(caps); @@ -301,38 +302,6 @@ void RouterContext::SetReachable() { UpdateRouterInfo(); } -void RouterContext::SetSupportsV6( - bool supportsV6) { - if (supportsV6) - m_RouterInfo.EnableV6(); - else - m_RouterInfo.DisableV6(); // TODO(anonimal): unused (we disable by default) - UpdateRouterInfo(); -} - -void RouterContext::SetSupportsNTCP(bool supportsNTCP) { - m_SupportsNTCP = supportsNTCP; - if(supportsNTCP && !m_RouterInfo.GetNTCPAddress()) - m_RouterInfo.AddNTCPAddress(m_Host, m_Port); - if(!supportsNTCP) - RemoveTransport(core::RouterInfo::Transport::NTCP); - UpdateRouterInfo(); -} - -void RouterContext::SetSupportsSSU(bool supportsSSU) { - m_SupportsSSU = supportsSSU; - if(supportsSSU && !m_RouterInfo.GetSSUAddress()) - m_RouterInfo.AddSSUAddress(m_Host, m_Port, m_RouterInfo.GetIdentHash()); - if(!supportsSSU) - RemoveTransport(core::RouterInfo::Transport::SSU); - // Remove SSU-related flags - m_RouterInfo.SetCaps(m_RouterInfo.GetCaps() - & ~core::RouterInfo::Cap::SSUTesting - & ~core::RouterInfo::Cap::SSUIntroducer); - - UpdateRouterInfo(); -} - void RouterContext::UpdateNTCPV6Address( const boost::asio::ip::address& host) { bool updated = false, @@ -368,7 +337,7 @@ void RouterContext::UpdateNTCPV6Address( } void RouterContext::UpdateStats() { - if (m_IsFloodfill) { + if (IsFloodfill()) { // update routers and leasesets m_RouterInfo.SetOption( ROUTER_INFO_OPTION_LEASESETS, @@ -395,6 +364,8 @@ std::shared_ptr RouterContext::GetTunnelPool() const { return kovri::core::tunnels.GetExploratoryPool(); } +// TODO(anonimal): no real reason to have message handling here, despite inheritance + void RouterContext::HandleI2NPMessage( const std::uint8_t* buf, std::size_t, @@ -418,6 +389,7 @@ void RouterContext::ProcessDeliveryStatusMessage( kovri::core::GarlicDestination::ProcessDeliveryStatusMessage(msg); } +// TODO(anonimal): uint64_t std::uint32_t RouterContext::GetUptime() const { return kovri::core::GetSecondsSinceEpoch () - m_StartupTime; } diff --git a/src/core/router/context.h b/src/core/router/context.h index ea98293e..d6e8f306 100644 --- a/src/core/router/context.h +++ b/src/core/router/context.h @@ -51,6 +51,7 @@ namespace kovri { namespace core { +// TODO(anonimal): refactoring const char ROUTER_INFO[] = "router.info"; const char ROUTER_KEYS[] = "router.keys"; const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes @@ -149,25 +150,11 @@ class RouterContext : public kovri::core::GarlicDestination { void SetReachable(); // @return true if we are a floodfill router otherwise false - bool IsFloodfill() const { - return m_IsFloodfill; + bool IsFloodfill() const + { + return m_Opts["floodfill"].as(); } - // Set if we are a floodfill router, rebuild RouterInfo. - // @param floodfill true if we want to become floodfill, false if we don't - void SetFloodfill( - bool floodfill); - - // Mark ourselves as having high bandwidth. - // Changes caps flags. - // Rebuilds RouterInfo. - void SetHighBandwidth(); - - // Mark ourselves as having low (aka NOT high) Bandwidth. - // Changes Capacity Flags. - // Rebuilds RouterInfo. - void SetLowBandwidth(); - // @return true if we are going to accept tunnels right now. bool AcceptsTunnels() const { return m_AcceptsTunnels; @@ -185,30 +172,6 @@ class RouterContext : public kovri::core::GarlicDestination { return m_RouterInfo.HasV6(); } - /// @return true if we support the NTCP transport, false otherwise - bool SupportsNTCP() const { - return m_SupportsNTCP; - } - - /// @return true if we support the SSU transport, false otherwise - bool SupportsSSU() const { - return m_SupportsSSU; - } - - // Set if we support IPv6 connectivity. - // Rebuilds RouterInfo. - // @param supportsV6 true if we support IPv6, false if we don't - void SetSupportsV6( - bool supportsV6); - - /// @brief Sets whether or not this router supports the NTCP transport - /// @param supportsNTCP true if NTCP is supported, false otherwise - void SetSupportsNTCP(bool supportsNTCP); - - /// @brief Sets whether or not this router supports the SSU transport - /// @param supportsNTCP true if SSU is supported, false otherwise - void SetSupportsSSU(bool supportsSSU); - // Called From NTCPSession. // Update our NTCP IPv6 address. // Rebuilds RouterInfo. @@ -254,46 +217,10 @@ class RouterContext : public kovri::core::GarlicDestination { void ProcessDeliveryStatusMessage( std::shared_ptr msg); - /** - * Note: these reseed functions are not ideal but - * they fit into our current design. We need to initialize - * here because we cannot (should not/don't need to) link - * unit-tests to executables (src/app) so, without these, - * current reseed tests won't compile. - */ - - /// @brief Sets user-supplied reseed stream - void SetOptionReseedFrom( - const std::string& stream) { - m_ReseedFrom = stream; - } - - /// @return User-supplied reseed stream - std::string GetOptionReseedFrom() const { - return m_ReseedFrom; - } - - /// @brief Sets user-supplied reseed SSL option - void SetOptionEnableSSL( - bool option) { - m_EnableSSL = option; - } - - /// @return User-supplied option to skip SSL - bool GetOptionEnableSSL() const { - return m_EnableSSL; - } - - /// @brief Sets user-supplied disable SU3 verification option - void SetOptionDisableSU3Verification(bool option) - { - m_DisableSU3Verification = option; - } - - /// @return User-supplied option to disable SU3 verification - bool GetOptionDisableSU3Verification() const + /// @brief Core router traits/options + const boost::program_options::variables_map& GetOpts() const { - return m_DisableSU3Verification; + return m_Opts; } /// @return root directory path @@ -316,17 +243,12 @@ class RouterContext : public kovri::core::GarlicDestination { kovri::core::RouterInfo m_RouterInfo; kovri::core::PrivateKeys m_Keys; std::uint64_t m_LastUpdateTime; - bool m_AcceptsTunnels, m_IsFloodfill; + bool m_AcceptsTunnels; std::uint64_t m_StartupTime; // in seconds since epoch RouterStatus m_Status; std::mutex m_GarlicMutex; - std::string m_Host; - std::uint16_t m_Port; - std::string m_ReseedFrom; - bool m_EnableSSL; - bool m_DisableSU3Verification; - bool m_SupportsNTCP, m_SupportsSSU; std::string m_CustomDataDir; + boost::program_options::variables_map m_Opts; }; extern RouterContext context; diff --git a/src/core/util/config.cc b/src/core/util/config.cc index 80fc3cbe..a77d0115 100644 --- a/src/core/util/config.cc +++ b/src/core/util/config.cc @@ -82,7 +82,7 @@ void Configuration::ParseConfig() // Map options values from command-line and config bpo::options_description system("\nsystem"); system.add_options()( - "host", bpo::value()->default_value("127.0.0.1"))( + "host", bpo::value()->default_value("127.0.0.1"))( // TODO(anonimal): fix default host "port,p", bpo::value()->default_value(0))( "data-dir", bpo::value() @@ -121,7 +121,7 @@ void Configuration::ParseConfig() "v6,6", bpo::value()->default_value(false)->value_name("bool"))( "floodfill,f", bpo::value()->default_value(false)->value_name("bool"))( - "bandwidth,b", bpo::value()->default_value("L"))( + "bandwidth,b", bpo::value()->default_value("L"))( // TODO(anonimal): refine + update packaged default config file "enable-ssu", bpo::value()->default_value(true)->value_name("bool"))( "enable-ntcp", From eb37e28d9c90d27e0196aea1412b33d5f3ff07ac Mon Sep 17 00:00:00 2001 From: anonimal Date: Thu, 16 Nov 2017 05:48:54 +0000 Subject: [PATCH 04/10] Core: return uint64_t for router uptime Epoch getter and startup time are both uint64_t --- src/client/api/i2p_control/session.cc | 3 ++- src/core/router/context.cc | 6 +++--- src/core/router/context.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/client/api/i2p_control/session.cc b/src/client/api/i2p_control/session.cc index cf5a8ea2..3d672935 100644 --- a/src/client/api/i2p_control/session.cc +++ b/src/client/api/i2p_control/session.cc @@ -248,7 +248,8 @@ void I2PControlSession::HandleRouterInfo( case RouterInfo::Uptime: response->SetParam( pair.first, - static_cast(core::context.GetUptime()) * 1000); + // TODO(unassigned): do not downcast from uint64_t! Requires interface work. + static_cast(core::context.GetUptime()) * 1000); // TODO(unassigned): multiplying will not bode well for the distant future... break; case RouterInfo::Version: diff --git a/src/core/router/context.cc b/src/core/router/context.cc index a8a897ff..e627c568 100644 --- a/src/core/router/context.cc +++ b/src/core/router/context.cc @@ -389,9 +389,9 @@ void RouterContext::ProcessDeliveryStatusMessage( kovri::core::GarlicDestination::ProcessDeliveryStatusMessage(msg); } -// TODO(anonimal): uint64_t -std::uint32_t RouterContext::GetUptime() const { - return kovri::core::GetSecondsSinceEpoch () - m_StartupTime; +std::uint64_t RouterContext::GetUptime() const +{ + return core::GetSecondsSinceEpoch () - m_StartupTime; } } // namespace core diff --git a/src/core/router/context.h b/src/core/router/context.h index d6e8f306..2b695277 100644 --- a/src/core/router/context.h +++ b/src/core/router/context.h @@ -86,7 +86,7 @@ class RouterContext : public kovri::core::GarlicDestination { } // @return How long this RouterContext has been online in seconds since epoch - std::uint32_t GetUptime() const; + std::uint64_t GetUptime() const; // @return Time that this RouterContext started in seconds since epoch std::uint32_t GetStartupTime() const { From 18aa94e1f9aeb3075b50087a392a990c5a798a18 Mon Sep 17 00:00:00 2001 From: anonimal Date: Fri, 17 Nov 2017 04:18:47 +0000 Subject: [PATCH 05/10] Core: don't use interface for context initialization - Clarifies ident creation logic without relying on interface members - Adds debug logging + TODOs --- src/core/router/context.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/core/router/context.cc b/src/core/router/context.cc index e627c568..a6f9707c 100644 --- a/src/core/router/context.cc +++ b/src/core/router/context.cc @@ -101,9 +101,19 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) LOG(debug) << "RouterContext: preparing RI creation"; core::RouterInfo router; - router.SetRouterIdentity(GetIdentity()); - router.AddSSUAddress(host, port, router.GetIdentHash()); + const IdentityEx& ident = m_Keys.GetPublic(); + const IdentHash& hash = ident.GetIdentHash(); + + LOG(debug) << "RouterContext: using ident: " << ident.ToBase64(); + LOG(debug) << "RouterContext: ident hash: " << hash.ToBase64(); + + // TODO(anonimal): new ctor, remove setters + router.SetRouterIdentity(ident); + + // TODO(anonimal): no point in adding if we're to remove later via bpo + router.AddSSUAddress(host, port, hash); router.AddNTCPAddress(host, port); + router.SetCaps( core::RouterInfo::Cap::Reachable // TODO(anonimal): but what if we've disabled run-time SSU... From a2a49aa9d2c0c83a34c2c33258ab4cfbf5883005 Mon Sep 17 00:00:00 2001 From: anonimal Date: Fri, 17 Nov 2017 12:18:08 +0000 Subject: [PATCH 06/10] Core: new RI ctor + fixes + WIP context init rewrite - related rewriting - context SSU caps fixes - zero initialize our SSU intro key - remove unnecessary address/port updating - add some logging, docs, and lots of TODOs --- src/core/router/context.cc | 97 +++++++++++++++----------------------- src/core/router/info.cc | 62 ++++++++++++++++++++---- src/core/router/info.h | 23 +++++++-- src/core/util/config.cc | 1 + src/util/routerinfo.cc | 3 +- 5 files changed, 116 insertions(+), 70 deletions(-) diff --git a/src/core/router/context.cc b/src/core/router/context.cc index a6f9707c..d04a62f1 100644 --- a/src/core/router/context.cc +++ b/src/core/router/context.cc @@ -73,11 +73,16 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) auto info_path = (path / ROUTER_INFO).string(); // Set host/port for RI creation/updating + // Note: host/port sanity checks done during configuration construction auto host = m_Opts["host"].as(); // TODO(anonimal): fix default host auto port = m_Opts["port"].defaulted() ? RandInRange32(RouterInfo::MinPort, RouterInfo::MaxPort) : m_Opts["port"].as(); + // Set available transports + bool has_ntcp = m_Opts["enable-ntcp"].as(); + bool has_ssu = m_Opts["enable-ssu"].as(); + // Set startup time m_StartupTime = core::GetSecondsSinceEpoch(); @@ -98,34 +103,13 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) m_Keys.ToBuffer(buf.data(), buf.size()); keys.Write(buf.data(), buf.size()); - LOG(debug) << "RouterContext: preparing RI creation"; - core::RouterInfo router; - - const IdentityEx& ident = m_Keys.GetPublic(); - const IdentHash& hash = ident.GetIdentHash(); - - LOG(debug) << "RouterContext: using ident: " << ident.ToBase64(); - LOG(debug) << "RouterContext: ident hash: " << hash.ToBase64(); - - // TODO(anonimal): new ctor, remove setters - router.SetRouterIdentity(ident); - - // TODO(anonimal): no point in adding if we're to remove later via bpo - router.AddSSUAddress(host, port, hash); - router.AddNTCPAddress(host, port); - - router.SetCaps( - core::RouterInfo::Cap::Reachable - // TODO(anonimal): but what if we've disabled run-time SSU... - | core::RouterInfo::Cap::SSUTesting - | core::RouterInfo::Cap::SSUIntroducer); - - // Set options - router.SetOption("netId", std::to_string(I2P_NETWORK_ID)); - router.SetOption("router.version", I2P_VERSION); - LOG(debug) << "RouterContext: creating RI from in-memory keys"; - router.CreateBuffer(m_Keys); + core::RouterInfo router( + m_Keys, + std::make_pair(host, port), + std::make_pair(has_ntcp, has_ssu)); // TODO(anonimal): brittle, see TODO in header + + // Update context RI m_RouterInfo.Update(router.GetBuffer(), router.GetBufferLen()); } else // Keys (and RI should also) exist @@ -138,17 +122,26 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) LOG(debug) << "RouterContext: updating existing RI " << info_path; core::RouterInfo router(info_path); - // Update address/port - const auto address = boost::asio::ip::address::from_string(host); - for (auto& router : m_RouterInfo.GetAddresses()) + // NTCP + if (has_ntcp && !router.GetNTCPAddress()) + router.AddNTCPAddress(host, port); + if (!has_ntcp) + RemoveTransport(core::RouterInfo::Transport::NTCP); + + // SSU + if (has_ssu && !router.GetSSUAddress()) + router.AddSSUAddress(host, port, router.GetIdentHash()); + if (!has_ssu) { - if (router.host != address && router.HasCompatibleHost(address)) - router.host = address; - if (router.port != port) - router.port = port; + RemoveTransport(core::RouterInfo::Transport::SSU); + + // Remove constructed SSU capabilities + router.SetCaps( + router.GetCaps() & ~core::RouterInfo::Cap::SSUTesting + & ~core::RouterInfo::Cap::SSUIntroducer); } - // Set RI options + // Update RI options (in case RI was older than these version) router.SetOption("coreVersion", I2P_VERSION); router.SetOption("router.version", I2P_VERSION); @@ -204,25 +197,6 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) } } - // NTCP - bool ntcp = m_Opts["enable-ntcp"].as(); - if (ntcp && !m_RouterInfo.GetNTCPAddress()) - m_RouterInfo.AddNTCPAddress(host, port); - if (!ntcp) - RemoveTransport(core::RouterInfo::Transport::NTCP); - - // SSU - bool ssu = m_Opts["enable-ssu"].as(); - if (ssu && !m_RouterInfo.GetSSUAddress()) - m_RouterInfo.AddSSUAddress(host, port, m_RouterInfo.GetIdentHash()); - if (!ssu) - RemoveTransport(core::RouterInfo::Transport::SSU); - - // Remove SSU-related flags - m_RouterInfo.SetCaps( - m_RouterInfo.GetCaps() & ~core::RouterInfo::Cap::SSUTesting - & ~core::RouterInfo::Cap::SSUIntroducer); - // Update RI/commit to disk UpdateRouterInfo(); } @@ -289,7 +263,7 @@ void RouterContext::SetReachable() { std::uint8_t caps = m_RouterInfo.GetCaps(); caps &= ~core::RouterInfo::Cap::Unreachable; caps |= core::RouterInfo::Cap::Reachable; - caps |= core::RouterInfo::Cap::SSUIntroducer; + caps |= core::RouterInfo::Cap::SSUIntroducer; // TODO(anonimal): but if SSU is disabled?... if (IsFloodfill()) caps |= core::RouterInfo::Cap::Floodfill; m_RouterInfo.SetCaps(caps); @@ -299,7 +273,7 @@ void RouterContext::SetReachable() { for (std::size_t i = 0; i < addresses.size(); i++) { if (addresses[i].transport == core::RouterInfo::Transport::SSU) { // insert NTCP address with host/port form SSU - m_RouterInfo.AddNTCPAddress( + m_RouterInfo.AddNTCPAddress( // TODO(anonimal): but if NTCP is disabled?... addresses[i].host.to_string().c_str(), addresses[i].port); break; @@ -308,8 +282,10 @@ void RouterContext::SetReachable() { // delete previous introducers for (auto& addr : addresses) addr.introducers.clear(); - // update - UpdateRouterInfo(); + + // TODO(anonimal): if we continue to use these setters (or a single template setter), + // we'll need to ensure router info is updated after setting (either through context + // or other means). } void RouterContext::UpdateNTCPV6Address( @@ -368,6 +344,11 @@ void RouterContext::RemoveTransport( break; } } + // Remove SSU capabilities + if (transport == core::RouterInfo::Transport::SSU) + m_RouterInfo.SetCaps( + m_RouterInfo.GetCaps() & ~core::RouterInfo::Cap::SSUTesting + & ~core::RouterInfo::Cap::SSUIntroducer); } std::shared_ptr RouterContext::GetTunnelPool() const { diff --git a/src/core/router/info.cc b/src/core/router/info.cc index 9b5e3c9a..f0ccbe22 100644 --- a/src/core/router/info.cc +++ b/src/core/router/info.cc @@ -45,32 +45,68 @@ #include "core/util/log.h" #include "core/util/timestamp.h" +#include "version.h" + namespace kovri { namespace core { -RouterInfo::RouterInfo() : m_Buffer(nullptr), m_Exception(__func__) // TODO(anonimal): buffer refactor +RouterInfo::RouterInfo() : m_Exception(__func__), m_Buffer(nullptr) // TODO(anonimal): buffer refactor { } -RouterInfo::~RouterInfo() +RouterInfo::RouterInfo( + const core::PrivateKeys& keys, + const std::pair& point, + const std::pair& has_transport, + const std::uint8_t caps) + : m_Exception(__func__), m_RouterIdentity(keys.GetPublic()) { + // TODO(anonimal): in core config, we guarantee validity of host and port but + // we don't guarantee here without said caller in place. + + // Log our identity + const IdentHash& hash = m_RouterIdentity.GetIdentHash(); + LOG(info) << "RouterInfo: our router's ident: " << m_RouterIdentity.ToBase64(); + LOG(info) << "RouterInfo: our router's ident hash: " << hash.ToBase64(); + + // Set default caps + SetCaps(caps); + + // Set default transports + if (has_transport.first) + AddNTCPAddress(point.first, point.second); + + if (has_transport.second) + { + AddSSUAddress(point.first, point.second, hash); + SetCaps( + m_Caps | core::RouterInfo::Cap::SSUTesting + | core::RouterInfo::Cap::SSUIntroducer); + } + + // Set default options + SetOption("netId", std::to_string(I2P_NETWORK_ID)); + SetOption("router.version", I2P_VERSION); + + // Set RI buffer + create RI + CreateBuffer(keys); } RouterInfo::RouterInfo(const std::string& path) - : m_Path(path), - m_Buffer(std::make_unique(Size::MaxBuffer)), // TODO(anonimal): buffer refactor - m_Exception(__func__) + : m_Exception(__func__), + m_Path(path), + m_Buffer(std::make_unique(Size::MaxBuffer)) // TODO(anonimal): buffer refactor { ReadFromFile(); ReadFromBuffer(false); } RouterInfo::RouterInfo(const std::uint8_t* buf, std::uint16_t len) - : m_Buffer(std::make_unique(Size::MaxBuffer)), // TODO(anonimal): buffer refactor - m_BufferLen(len), - m_Exception(__func__) + : m_Exception(__func__), + m_Buffer(std::make_unique(Size::MaxBuffer)), // TODO(anonimal): buffer refactor + m_BufferLen(len) { if (!buf) throw std::invalid_argument("RouterInfo: null buffer"); @@ -81,6 +117,10 @@ RouterInfo::RouterInfo(const std::uint8_t* buf, std::uint16_t len) m_IsUpdated = true; } +RouterInfo::~RouterInfo() +{ +} + void RouterInfo::ReadFromFile() { try @@ -277,6 +317,7 @@ void RouterInfo::ParseRouterInfo(const std::string& router_info) address.mtu = boost::lexical_cast(value); break; case Trait::Key: + // Our intro key as introducer kovri::core::Base64ToByteStream( value.c_str(), value.size(), address.key, 32); break; @@ -476,6 +517,7 @@ const std::string RouterInfo::GetCapsFlags() const return flags; } +// TODO(unassigned): remove. This is only used for unrefactored kovri-util RI creation void RouterInfo::SetRouterIdentity(const IdentityEx& identity) { m_RouterIdentity = identity; @@ -664,6 +706,7 @@ void RouterInfo::CreateRouterInfo( core::StringStream& router_info, const PrivateKeys& private_keys) { + // TODO(anonimal): more useful logging LOG(debug) << "RouterInfo: " << __func__; // Write ident @@ -965,6 +1008,9 @@ const std::string RouterInfo::GetDescription( << tabs << "\t" << GetTrait(Trait::Cost) << delimiter << static_cast(address.cost) << terminator + // TODO(anonimal): initialization order is brittle: if SSU is not parsed before NTCP, + // GetDescription will log base64 of zero-initialized address key memory. + // Only log key if transport is SSU. << tabs << "\t" << GetTrait(Trait::Key) << delimiter << address.key.ToBase64() << terminator; diff --git a/src/core/router/info.h b/src/core/router/info.h index 9cb61b60..6e873f98 100644 --- a/src/core/router/info.h +++ b/src/core/router/info.h @@ -398,6 +398,17 @@ class RouterInfo : public RouterInfoTraits, public RoutingDestination RouterInfo(); ~RouterInfo(); + /// @brief Create RI with standard defaults + /// @param point Local hostname/ip address + port + /// @param has_transport Supports NTCP, SSU + /// @param keys Privkeys which generate identity + /// @param caps RI capabilities + RouterInfo( + const core::PrivateKeys& keys, + const std::pair& point, + const std::pair& has_transport, // TODO(anonimal): refactor as bitwise SupportedTransport? + const std::uint8_t caps = core::RouterInfo::Cap::Reachable); + /// @brief Create RI from file /// @param path Full path to RI file RouterInfo(const std::string& path); @@ -426,7 +437,7 @@ class RouterInfo : public RouterInfoTraits, public RoutingDestination std::uint64_t date{}; std::uint8_t cost{}; // SSU only - Tag<32> key; // intro key for SSU + Tag<32> key{}; // Our intro key for SSU std::vector introducers; bool HasCompatibleHost(const boost::asio::ip::address& other) const noexcept { @@ -434,9 +445,13 @@ class RouterInfo : public RouterInfoTraits, public RoutingDestination } }; + // TODO(unassigned): remove. This is only used for unrefactored kovri-util RI creation /// @brief Set RI identity and current timestamp void SetRouterIdentity(const IdentityEx& identity); + + // TODO(anonimal): template address adder + /// @brief Adds SSU address to RI /// @details Sets RI members appropriately, saves address object void AddNTCPAddress(const std::string& host, std::uint16_t port); @@ -485,11 +500,13 @@ class RouterInfo : public RouterInfoTraits, public RoutingDestination /// @param path Full RI path of file to save to void SaveToFile(const std::string& path); - // TODO(anonimal): not an ideal getter /// @brief Get RI profile /// @detail If profile does not exist, creates it + // TODO(anonimal): not an ideal getter because of detail std::shared_ptr GetProfile() const; + // TODO(anonimal): template address getter + /// @return Address object capable of NTCP /// @param has_v6 Address should have v6 capability const Address* GetNTCPAddress(bool has_v6 = false) const; @@ -755,6 +772,7 @@ class RouterInfo : public RouterInfoTraits, public RoutingDestination const RouterInfo::Address* GetAddress(const std::uint8_t transports) const; private: + core::Exception m_Exception; std::string m_Path; IdentityEx m_RouterIdentity; std::unique_ptr m_Buffer; @@ -765,7 +783,6 @@ class RouterInfo : public RouterInfoTraits, public RoutingDestination bool m_IsUpdated = false, m_IsUnreachable = false; std::uint8_t m_SupportedTransports{}, m_Caps{}; mutable std::shared_ptr m_Profile; - core::Exception m_Exception; }; } // namespace core diff --git a/src/core/util/config.cc b/src/core/util/config.cc index a77d0115..d7e15934 100644 --- a/src/core/util/config.cc +++ b/src/core/util/config.cc @@ -185,6 +185,7 @@ void Configuration::ParseConfigFile( bpo::store(bpo::parse_config_file(filename, options), var_map); bpo::notify(var_map); + // TODO(anonimal): move to sanity check function for namespace use // Check host syntax boost::system::error_code ec; boost::asio::ip::address::from_string(m_Map["host"].as(), ec); diff --git a/src/util/routerinfo.cc b/src/util/routerinfo.cc index 883e9adb..d028e6d6 100644 --- a/src/util/routerinfo.cc +++ b/src/util/routerinfo.cc @@ -117,6 +117,7 @@ bool RouterInfoCommand::Impl( core::RouterInfo::MaxPort) : vm["port"].as(); + // TODO(unassigned): refactor according to new RI ctor interface // Generate private key core::PrivateKeys keys = core::PrivateKeys::CreateRandomKeys( core::DEFAULT_ROUTER_SIGNING_KEY_TYPE); @@ -141,7 +142,7 @@ bool RouterInfoCommand::Impl( routerInfo.SetCaps( routerInfo.GetCaps() | core::RouterInfo::Cap::HighBandwidth); // Set options - routerInfo.SetOption("netId", std::to_string(vm["netid"].as())); + routerInfo.SetOption("netId", std::to_string(vm["netid"].as())); // TODO(unassigned): changing netId is (and may always be) unecessary routerInfo.SetOption("router.version", I2P_VERSION); routerInfo.CreateBuffer(keys); From b254beb93bcb7f50975914542f39079fcf515940 Mon Sep 17 00:00:00 2001 From: anonimal Date: Fri, 17 Nov 2017 12:29:11 +0000 Subject: [PATCH 07/10] Core: fix description logging of SSU address key --- src/core/router/info.cc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/router/info.cc b/src/core/router/info.cc index f0ccbe22..a1f2c0d1 100644 --- a/src/core/router/info.cc +++ b/src/core/router/info.cc @@ -1006,18 +1006,16 @@ const std::string RouterInfo::GetDescription( << address.date << terminator << tabs << "\t" << GetTrait(Trait::Cost) << delimiter - << static_cast(address.cost) << terminator - - // TODO(anonimal): initialization order is brittle: if SSU is not parsed before NTCP, - // GetDescription will log base64 of zero-initialized address key memory. - // Only log key if transport is SSU. - << tabs << "\t" << GetTrait(Trait::Key) << delimiter - << address.key.ToBase64() << terminator; + << static_cast(address.cost) << terminator; if (address.transport == Transport::SSU) { - ss << tabs << "\n\tIntroducers(" << address.introducers.size() << ")" + ss << tabs << "\t" << GetTrait(Trait::Key) << delimiter + << address.key.ToBase64() << terminator + + << tabs << "\n\tIntroducers(" << address.introducers.size() << ")" << std::endl; + for (const Introducer& introducer : address.introducers) ss << GetDescription(introducer, tabs + "\t\t") << std::endl; } From 1f14b6551c1d1f652e018178876a8cea63fa96f2 Mon Sep 17 00:00:00 2001 From: anonimal Date: Fri, 17 Nov 2017 22:24:38 +0000 Subject: [PATCH 08/10] Core: context/RI trait and state refactor --- src/client/api/i2p_control/session.cc | 2 +- src/core/router/context.cc | 25 ++++++----- src/core/router/context.h | 53 ++++++++++------------- src/core/router/info.cc | 4 +- src/core/router/info.h | 38 ++++++++++++++++ src/core/router/transports/impl.cc | 4 +- src/core/router/transports/ssu/server.cc | 4 +- src/core/router/transports/ssu/session.cc | 10 ++--- 8 files changed, 86 insertions(+), 54 deletions(-) diff --git a/src/client/api/i2p_control/session.cc b/src/client/api/i2p_control/session.cc index 3d672935..8564368a 100644 --- a/src/client/api/i2p_control/session.cc +++ b/src/client/api/i2p_control/session.cc @@ -274,7 +274,7 @@ void I2PControlSession::HandleRouterInfo( case RouterInfo::NetStatus: response->SetParam( pair.first, - static_cast(core::context.GetStatus())); + static_cast(core::context.GetState())); break; case RouterInfo::TunnelsParticipating: diff --git a/src/core/router/context.cc b/src/core/router/context.cc index d04a62f1..b6dcdf15 100644 --- a/src/core/router/context.cc +++ b/src/core/router/context.cc @@ -38,6 +38,7 @@ #include #include "core/router/i2np.h" +#include "core/router/info.h" #include "core/router/net_db/impl.h" #include "core/util/filesystem.h" @@ -58,7 +59,7 @@ RouterContext::RouterContext() : m_LastUpdateTime(0), m_AcceptsTunnels(true), m_StartupTime(0), - m_Status(eRouterStatusOK) {} + m_State(RouterState::OK) {} // TODO(anonimal): review context's RI initialization options // TODO(anonimal): determine which functions are truly context and which are RI @@ -69,8 +70,8 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) // Set paths auto path = core::EnsurePath(core::GetCorePath()); - auto keys_path = (path / ROUTER_KEYS).string(); - auto info_path = (path / ROUTER_INFO).string(); + auto keys_path = (path / GetTrait(Trait::KeyFile)).string(); + auto info_path = (path / GetTrait(Trait::InfoFile)).string(); // Set host/port for RI creation/updating // Note: host/port sanity checks done during configuration construction @@ -142,8 +143,8 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) } // Update RI options (in case RI was older than these version) - router.SetOption("coreVersion", I2P_VERSION); - router.SetOption("router.version", I2P_VERSION); + router.SetOption(GetTrait(Trait::CoreVersion), I2P_VERSION); + router.SetOption(GetTrait(Trait::RouterVersion), I2P_VERSION); // Update context RI m_RouterInfo.Update(router.GetBuffer(), router.GetBufferLen()); @@ -176,8 +177,8 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) m_RouterInfo.SetCaps( m_RouterInfo.GetCaps() & ~core::RouterInfo::Cap::Floodfill); // we don't publish number of routers and leaseset for non-floodfill - m_RouterInfo.GetOptions().erase(ROUTER_INFO_OPTION_LEASESETS); - m_RouterInfo.GetOptions().erase(ROUTER_INFO_OPTION_ROUTERS); + m_RouterInfo.GetOptions().erase(GetTrait(Trait::LeaseSets)); + m_RouterInfo.GetOptions().erase(GetTrait(Trait::Routers)); } // Bandcaps @@ -197,6 +198,7 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) } } + // TODO(anonimal): we don't want to update twice when once at the right time will suffice // Update RI/commit to disk UpdateRouterInfo(); } @@ -204,7 +206,8 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) void RouterContext::UpdateRouterInfo() { LOG(debug) << "RouterContext: updating RI, saving to file"; m_RouterInfo.CreateBuffer(m_Keys); - m_RouterInfo.SaveToFile((kovri::core::GetCorePath() / ROUTER_INFO).string()); + m_RouterInfo.SaveToFile( + (core::GetCorePath() / GetTrait(Trait::InfoFile)).string()); m_LastUpdateTime = kovri::core::GetSecondsSinceEpoch(); } @@ -218,7 +221,7 @@ void RouterContext::UpdateAddress( } } auto ts = kovri::core::GetSecondsSinceEpoch(); - if (updated || ts > m_LastUpdateTime + ROUTER_INFO_UPDATE_INTERVAL) + if (updated || ts > m_LastUpdateTime + Interval::Update) UpdateRouterInfo(); } @@ -326,10 +329,10 @@ void RouterContext::UpdateStats() { if (IsFloodfill()) { // update routers and leasesets m_RouterInfo.SetOption( - ROUTER_INFO_OPTION_LEASESETS, + GetTrait(Trait::LeaseSets), boost::lexical_cast(kovri::core::netdb.GetNumLeaseSets())); m_RouterInfo.SetOption( - ROUTER_INFO_OPTION_ROUTERS, + GetTrait(Trait::Routers), boost::lexical_cast(kovri::core::netdb.GetNumRouters())); UpdateRouterInfo(); } diff --git a/src/core/router/context.h b/src/core/router/context.h index 2b695277..9b735f85 100644 --- a/src/core/router/context.h +++ b/src/core/router/context.h @@ -51,21 +51,20 @@ namespace kovri { namespace core { -// TODO(anonimal): refactoring -const char ROUTER_INFO[] = "router.info"; -const char ROUTER_KEYS[] = "router.keys"; -const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes - -const char ROUTER_INFO_OPTION_LEASESETS[] = "netdb.knownLeaseSets"; -const char ROUTER_INFO_OPTION_ROUTERS[] = "netdb.knownRouters"; - -enum RouterStatus { - eRouterStatusOK = 0, - eRouterStatusTesting = 1, - eRouterStatusFirewalled = 2 + +enum struct RouterState : std::uint8_t +{ + /// @brief Context is fully port forwarded + OK, + + /// @brief Context is testing connectivity + Testing, + + /// @brief Context detects being firewalled + Firewalled, }; -class RouterContext : public kovri::core::GarlicDestination { +class RouterContext : public RouterInfoTraits, public GarlicDestination { public: RouterContext(); @@ -98,27 +97,19 @@ class RouterContext : public kovri::core::GarlicDestination { return m_LastUpdateTime; } - // @return - // eRouterStatusOk - if the RouterContext is fully port forwarded, - // eRouterStatusTesting - if the RouterContext is testing connectivity - // eRouterStatusFirewalled - if the RouterContext detects being firewalled - RouterStatus GetStatus() const { - return m_Status; + /// @return Router state + RouterState GetState() const noexcept + { + return m_State; } - // Set RouterContext's Status - // @see GetStatus - // @param status the new status this RouterContext will have - void SetStatus( - RouterStatus status) { - m_Status = status; + /// @brief Set context state + // @param status the new state this context will have + void SetState(RouterState state) noexcept + { + m_State = state; } - // Called from Daemon, updates this RouterContext's Port. - // Rebuilds RouterInfo - // @param port port number - void UpdatePort(std::uint16_t port); - // Called From SSU or Daemon. // Update Our IP Address, external IP Address if behind NAT. // Rebuilds RouterInfo @@ -245,7 +236,7 @@ class RouterContext : public kovri::core::GarlicDestination { std::uint64_t m_LastUpdateTime; bool m_AcceptsTunnels; std::uint64_t m_StartupTime; // in seconds since epoch - RouterStatus m_Status; + RouterState m_State; std::mutex m_GarlicMutex; std::string m_CustomDataDir; boost::program_options::variables_map m_Opts; diff --git a/src/core/router/info.cc b/src/core/router/info.cc index a1f2c0d1..1e9f00da 100644 --- a/src/core/router/info.cc +++ b/src/core/router/info.cc @@ -87,8 +87,8 @@ RouterInfo::RouterInfo( } // Set default options - SetOption("netId", std::to_string(I2P_NETWORK_ID)); - SetOption("router.version", I2P_VERSION); + SetOption(GetTrait(Trait::NetID), std::to_string(I2P_NETWORK_ID)); + SetOption(GetTrait(Trait::RouterVersion), I2P_VERSION); // Set RI buffer + create RI CreateBuffer(keys); diff --git a/src/core/router/info.h b/src/core/router/info.h index 6e873f98..194e0632 100644 --- a/src/core/router/info.h +++ b/src/core/router/info.h @@ -56,6 +56,10 @@ namespace core { struct RouterInfoTraits { + /// @enum Interval + /// @brief RI intervals + enum Interval { Update = 1800 }; // 30 minutes + /// @enum Size /// @brief Router Info size constants enum Size : std::uint16_t @@ -133,6 +137,17 @@ struct RouterInfoTraits /// @brief RI traits enum struct Trait : std::uint8_t { + // File-specific + InfoFile, + KeyFile, + + // Option-specific + RouterVersion, + CoreVersion, + LeaseSets, + Routers, + NetID, + // Address-specific NTCP, SSU, @@ -164,6 +179,29 @@ struct RouterInfoTraits { switch (trait) { + // File names + case Trait::InfoFile: + return "router.info"; + + case Trait::KeyFile: + return "router.key"; + + // Option-specific + case Trait::RouterVersion: + return "router.version"; + + case Trait::CoreVersion: + return "coreVersion"; + + case Trait::LeaseSets: + return "netdb.knownLeaseSets"; + + case Trait::Routers: + return "netdb.knownRouters"; + + case Trait::NetID: + return "netId"; + // Address-specific case Trait::NTCP: return "NTCP"; diff --git a/src/core/router/transports/impl.cc b/src/core/router/transports/impl.cc index 8e0d8f2e..928e46a0 100644 --- a/src/core/router/transports/impl.cc +++ b/src/core/router/transports/impl.cc @@ -524,7 +524,7 @@ void Transports::DetectExternalIP() { LOG(error) << "Transports: can't detect external IP, SSU is not available"; return; } - context.SetStatus(eRouterStatusTesting); + context.SetState(RouterState::Testing); // TODO(unassigned): Why 5 times? (make constant) for (int i = 0; i < 5; i++) { auto router = kovri::core::netdb.GetRandomPeerTestRouter(); @@ -620,7 +620,7 @@ void Transports::HandlePeerCleanupTimer( } UpdateBandwidth(); // TODO(unassigned): use separate timer(s) for it // if still testing, repeat peer test - if (context.GetStatus() == eRouterStatusTesting) + if (context.GetState() == RouterState::Testing) DetectExternalIP(); m_PeerCleanupTimer.expires_from_now( boost::posix_time::seconds( diff --git a/src/core/router/transports/ssu/server.cc b/src/core/router/transports/ssu/server.cc index 318dc47e..8b0bad2b 100644 --- a/src/core/router/transports/ssu/server.cc +++ b/src/core/router/transports/ssu/server.cc @@ -483,12 +483,12 @@ void SSUServer::HandleIntroducersUpdateTimer( LOG(debug) << "SSUServer: handling introducers update timer"; if (ecode != boost::asio::error::operation_aborted) { // timeout expired - if (context.GetStatus() == eRouterStatusTesting) { + if (context.GetState() == RouterState::Testing) { // we still don't know if we need introducers ScheduleIntroducersUpdateTimer(); return; } - if (context.GetStatus () == eRouterStatusOK) + if (context.GetState () == RouterState::OK) return; // we don't need introducers anymore // we are firewalled if (!context.IsUnreachable()) context.SetUnreachable(); diff --git a/src/core/router/transports/ssu/session.cc b/src/core/router/transports/ssu/session.cc index fa4e1e9e..6b106c74 100644 --- a/src/core/router/transports/ssu/session.cc +++ b/src/core/router/transports/ssu/session.cc @@ -342,7 +342,7 @@ void SSUSession::SendSessionRequest() { packet.SetDhX(m_DHKeysPair->public_key.data()); // Fill extended options std::array extended_data {{ 0x00, 0x00 }}; - if (context.GetStatus() == eRouterStatusOK) { // we don't need relays + if (context.GetState() == RouterState::OK) { // we don't need relays packet.GetHeader()->SetExtendedOptions(true); packet.GetHeader()->SetExtendedOptionsData(extended_data.data(), 2); } @@ -873,13 +873,13 @@ void SSUSession::ProcessPeerTest( LOG(debug) << "SSUSession:" << GetFormattedSessionInfo() << "PeerTest from Bob. We are Alice"; - if (context.GetStatus() == eRouterStatusTesting) // still not OK - context.SetStatus(eRouterStatusFirewalled); + if (context.GetState() == RouterState::Testing) // still not OK + context.SetState(RouterState::Firewalled); } else { LOG(debug) << "SSUSession:" << GetFormattedSessionInfo() << "first PeerTest from Charlie. We are Alice"; - context.SetStatus(eRouterStatusOK); + context.SetState(RouterState::OK); m_Server.UpdatePeerTest( packet->GetNonce(), PeerTestParticipant::Alice2); @@ -903,7 +903,7 @@ void SSUSession::ProcessPeerTest( LOG(debug) << "SSUSession:" << GetFormattedSessionInfo() << "second PeerTest from Charlie. We are Alice"; - context.SetStatus(eRouterStatusOK); + context.SetState(RouterState::OK); m_Server.RemovePeerTest(packet->GetNonce()); } break; From 872c70e22130f5c7dcd9283310bf68aa2b0b5eee Mon Sep 17 00:00:00 2001 From: anonimal Date: Sat, 18 Nov 2017 00:49:35 +0000 Subject: [PATCH 09/10] Core: rewrite RI address add'er Note: template function was not needed afterall. --- src/core/router/context.cc | 26 +++++++------ src/core/router/info.cc | 78 +++++++++++++++++++++++--------------- src/core/router/info.h | 23 +++++------ src/util/routerinfo.cc | 7 +++- src/util/routerinfo.h | 4 +- 5 files changed, 78 insertions(+), 60 deletions(-) diff --git a/src/core/router/context.cc b/src/core/router/context.cc index b6dcdf15..7b1481df 100644 --- a/src/core/router/context.cc +++ b/src/core/router/context.cc @@ -36,6 +36,7 @@ #include #include +#include #include "core/router/i2np.h" #include "core/router/info.h" @@ -125,13 +126,14 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) // NTCP if (has_ntcp && !router.GetNTCPAddress()) - router.AddNTCPAddress(host, port); + router.AddAddress(std::make_tuple(Transport::NTCP, host, port)); if (!has_ntcp) RemoveTransport(core::RouterInfo::Transport::NTCP); // SSU if (has_ssu && !router.GetSSUAddress()) - router.AddSSUAddress(host, port, router.GetIdentHash()); + router.AddAddress( + std::make_tuple(Transport::SSU, host, port), router.GetIdentHash()); if (!has_ssu) { RemoveTransport(core::RouterInfo::Transport::SSU); @@ -276,9 +278,11 @@ void RouterContext::SetReachable() { for (std::size_t i = 0; i < addresses.size(); i++) { if (addresses[i].transport == core::RouterInfo::Transport::SSU) { // insert NTCP address with host/port form SSU - m_RouterInfo.AddNTCPAddress( // TODO(anonimal): but if NTCP is disabled?... - addresses[i].host.to_string().c_str(), - addresses[i].port); + m_RouterInfo.AddAddress( // TODO(anonimal): but if NTCP is disabled?... + std::make_tuple( + Transport::NTCP, + addresses[i].host.to_string(), + addresses[i].port)); break; } } @@ -311,14 +315,12 @@ void RouterContext::UpdateNTCPV6Address( } if (!found) { // create new address - m_RouterInfo.AddNTCPAddress( - host.to_string().c_str(), - port); - m_RouterInfo.AddSSUAddress( - host.to_string().c_str(), - port, + m_RouterInfo.AddAddress( + std::make_tuple(Transport::NTCP, host.to_string(), port)); + m_RouterInfo.AddAddress( + std::make_tuple(Transport::SSU, host.to_string(), port), GetIdentHash(), - kovri::core::GetMTU(host)); + core::GetMTU(host)); updated = true; } if (updated) diff --git a/src/core/router/info.cc b/src/core/router/info.cc index 1e9f00da..c50cf95a 100644 --- a/src/core/router/info.cc +++ b/src/core/router/info.cc @@ -36,6 +36,7 @@ #include #include +#include #include "core/router/context.h" @@ -76,11 +77,12 @@ RouterInfo::RouterInfo( // Set default transports if (has_transport.first) - AddNTCPAddress(point.first, point.second); + AddAddress(std::make_tuple(Transport::NTCP, point.first, point.second)); if (has_transport.second) { - AddSSUAddress(point.first, point.second, hash); + AddAddress( + std::make_tuple(Transport::SSU, point.first, point.second), hash); SetCaps( m_Caps | core::RouterInfo::Cap::SSUTesting | core::RouterInfo::Cap::SSUIntroducer); @@ -524,39 +526,53 @@ void RouterInfo::SetRouterIdentity(const IdentityEx& identity) m_Timestamp = kovri::core::GetMillisecondsSinceEpoch(); } -void RouterInfo::AddNTCPAddress(const std::string& host, std::uint16_t port) -{ - Address addr; - addr.host = boost::asio::ip::address::from_string(host); - addr.port = port; - addr.transport = Transport::NTCP; - addr.cost = Size::NTCPCost; - addr.date = 0; - addr.mtu = 0; - m_Addresses.push_back(addr); - m_SupportedTransports |= addr.host.is_v6() ? SupportedTransport::NTCPv6 - : SupportedTransport::NTCPv4; -} - -void RouterInfo::AddSSUAddress( - const std::string& host, - std::uint16_t port, +void RouterInfo::AddAddress( + const std::tuple& point, const std::uint8_t* key, - std::uint16_t mtu) + const std::uint16_t mtu) { Address addr; - addr.host = boost::asio::ip::address::from_string(host); - addr.port = port; - addr.transport = Transport::SSU; - addr.cost = Size::SSUCost; - addr.date = 0; - addr.mtu = mtu; - std::memcpy(addr.key, key, 32); + addr.transport = std::get<0>(point); + addr.host = boost::asio::ip::address::from_string(std::get<1>(point)); + addr.port = std::get<2>(point); + addr.date = 0; // TODO(anonimal): ?... + + // Set transport-specific + switch (addr.transport) + { + case Transport::NTCP: + { + addr.cost = Size::NTCPCost; + addr.mtu = 0; // TODO(anonimal): ?... + m_SupportedTransports |= addr.host.is_v6() + ? SupportedTransport::NTCPv6 + : SupportedTransport::NTCPv4; + } + break; + + case Transport::SSU: + { + addr.cost = Size::SSUCost; + addr.mtu = mtu; + if (!key) + throw std::runtime_error("RouterInfo: null SSU intro key"); + addr.key = key; + m_SupportedTransports |= addr.host.is_v6() + ? SupportedTransport::SSUv6 + : SupportedTransport::SSUv4; + // Set our caps + m_Caps |= Cap::SSUTesting | Cap::SSUIntroducer; + } + break; + + default: + throw std::runtime_error( + "RouterInfo: " + std::string(__func__) + ": unsupported transport"); + break; + } + + // Save address m_Addresses.push_back(addr); - m_SupportedTransports |= - addr.host.is_v6() ? SupportedTransport::SSUv6 : SupportedTransport::SSUv4; - m_Caps |= Cap::SSUTesting; - m_Caps |= Cap::SSUIntroducer; } bool RouterInfo::AddIntroducer(const Address* address, std::uint32_t tag) diff --git a/src/core/router/info.h b/src/core/router/info.h index 194e0632..b6058847 100644 --- a/src/core/router/info.h +++ b/src/core/router/info.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include "core/crypto/signature.h" @@ -487,20 +488,14 @@ class RouterInfo : public RouterInfoTraits, public RoutingDestination /// @brief Set RI identity and current timestamp void SetRouterIdentity(const IdentityEx& identity); - - // TODO(anonimal): template address adder - - /// @brief Adds SSU address to RI - /// @details Sets RI members appropriately, saves address object - void AddNTCPAddress(const std::string& host, std::uint16_t port); - - /// @brief Adds SSU address to RI - /// @details Sets RI members appropriately, saves address object - void AddSSUAddress( - const std::string& host, - std::uint16_t port, - const std::uint8_t* key, - std::uint16_t mtu = 0); + /// @brief Adds/saves address + sets appropriate RI members + /// @param point Supported transport / Host string / Port integral + /// @param key Our intoducer key + /// @param mtu Address MTU + void AddAddress( + const std::tuple& point, + const std::uint8_t* key = nullptr, + const std::uint16_t mtu = 0); /// @brief Adds introducer to RI using SSU capable address object /// @param address SSU capable address diff --git a/src/util/routerinfo.cc b/src/util/routerinfo.cc index d028e6d6..214bbbac 100644 --- a/src/util/routerinfo.cc +++ b/src/util/routerinfo.cc @@ -31,6 +31,7 @@ #include "util/routerinfo.h" #include #include +#include #include "core/crypto/rand.h" #include "core/router/info.h" @@ -124,8 +125,10 @@ bool RouterInfoCommand::Impl( // Set router info attributes core::RouterInfo routerInfo; routerInfo.SetRouterIdentity(keys.GetPublic()); - routerInfo.AddSSUAddress(host, port, routerInfo.GetIdentHash()); - routerInfo.AddNTCPAddress(host, port); + routerInfo.AddAddress(std::make_tuple(Transport::NTCP, host, port)); + routerInfo.AddAddress( + std::make_tuple(Transport::SSU, host, port), + routerInfo.GetIdentHash()); // Set capabilities routerInfo.SetCaps(core::RouterInfo::Cap::Reachable); if (vm["ssuintroducer"].as()) diff --git a/src/util/routerinfo.h b/src/util/routerinfo.h index 5527c679..60396d8f 100644 --- a/src/util/routerinfo.h +++ b/src/util/routerinfo.h @@ -37,12 +37,14 @@ #include #include "util/command.h" +#include "core/router/info.h" + /** * @class RouterInfoCommand * @brief base class for routerinfo */ -class RouterInfoCommand : public Command +class RouterInfoCommand : public Command, public kovri::core::RouterInfoTraits { public: RouterInfoCommand(); From 771340faf0dc77e21e860ef71ae6fe3c4647f8d1 Mon Sep 17 00:00:00 2001 From: anonimal Date: Sat, 18 Nov 2017 11:14:34 +0000 Subject: [PATCH 10/10] Core: default RI opts setter + remove deprecation - coreVersion option was removed in 0.9.24 - adds RI options debug logging --- src/core/router/context.cc | 5 +---- src/core/router/info.cc | 17 ++++++++++++++--- src/core/router/info.h | 7 +++---- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/core/router/context.cc b/src/core/router/context.cc index 7b1481df..c478d996 100644 --- a/src/core/router/context.cc +++ b/src/core/router/context.cc @@ -46,8 +46,6 @@ #include "core/util/mtu.h" #include "core/util/timestamp.h" -#include "version.h" - namespace kovri { namespace core @@ -145,8 +143,7 @@ void RouterContext::Initialize(const boost::program_options::variables_map& map) } // Update RI options (in case RI was older than these version) - router.SetOption(GetTrait(Trait::CoreVersion), I2P_VERSION); - router.SetOption(GetTrait(Trait::RouterVersion), I2P_VERSION); + router.SetDefaultOptions(); // Update context RI m_RouterInfo.Update(router.GetBuffer(), router.GetBufferLen()); diff --git a/src/core/router/info.cc b/src/core/router/info.cc index c50cf95a..095936d3 100644 --- a/src/core/router/info.cc +++ b/src/core/router/info.cc @@ -89,8 +89,7 @@ RouterInfo::RouterInfo( } // Set default options - SetOption(GetTrait(Trait::NetID), std::to_string(I2P_NETWORK_ID)); - SetOption(GetTrait(Trait::RouterVersion), I2P_VERSION); + SetDefaultOptions(); // Set RI buffer + create RI CreateBuffer(keys); @@ -434,6 +433,15 @@ void RouterInfo::ParseRouterInfo(const std::string& router_info) } } +void RouterInfo::SetDefaultOptions() +{ + SetOption(GetTrait(Trait::NetID), std::to_string(I2P_NETWORK_ID)); + SetOption(GetTrait(Trait::RouterVersion), I2P_VERSION); + // TODO(anonimal): implement known lease-sets and known routers. + // We current only set default options when starting/creating RI *before* + // netdb starts. We'll need to ensure the 'known' opts are set *after* netdb starts. +} + void RouterInfo::SetCaps(const std::string& caps) { LOG(debug) << "RouterInfo: " << __func__ << ": setting caps " << caps; @@ -871,7 +879,10 @@ void RouterInfo::CreateRouterInfo( // Write remaining options for (const auto& opt : GetOptions()) - options.WriteKeyPair(opt.first, opt.second); + { + LOG(debug) << "RouterInfo: writing: " << opt.first << "=" << opt.second; + options.WriteKeyPair(opt.first, opt.second); + } // Write size of remaining options std::uint16_t size = htobe16(options.Str().size()); diff --git a/src/core/router/info.h b/src/core/router/info.h index b6058847..29c2b206 100644 --- a/src/core/router/info.h +++ b/src/core/router/info.h @@ -144,7 +144,6 @@ struct RouterInfoTraits // Option-specific RouterVersion, - CoreVersion, LeaseSets, Routers, NetID, @@ -191,9 +190,6 @@ struct RouterInfoTraits case Trait::RouterVersion: return "router.version"; - case Trait::CoreVersion: - return "coreVersion"; - case Trait::LeaseSets: return "netdb.knownLeaseSets"; @@ -625,6 +621,9 @@ class RouterInfo : public RouterInfoTraits, public RoutingDestination m_Options[key] = value; } + /// @brief Set essential (non-caps) default options for new RIs and when updating RIs + void SetDefaultOptions(); + /// @return Mutable RI options std::map& GetOptions() noexcept {