diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index fd0c5a22..73bd8077 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -24,7 +24,7 @@ namespace transport m_AddressV4 (boost::asio::ip::address_v4()), m_AddressV6 (boost::asio::ip::address_v6()), m_TerminationTimer (GetService ()), m_ResendTimer (GetService ()), m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()), - m_IsPublished (true) + m_IsPublished (true), m_IsSyncClockFromPeers (true) { } @@ -34,6 +34,7 @@ namespace transport { StartIOService (); i2p::config::GetOption ("ssu2.published", m_IsPublished); + i2p::config::GetOption("nettime.frompeers", m_IsSyncClockFromPeers); bool found = false; auto& addresses = i2p::context.GetRouterInfo ().GetAddresses (); for (const auto& address: addresses) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 8bada7a6..8ad64692 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -56,6 +56,7 @@ namespace transport void SetLocalAddress (const boost::asio::ip::address& localAddress); bool IsSupported (const boost::asio::ip::address& addr) const; uint16_t GetPort (bool v4) const; + bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; void AddSession (std::shared_ptr session); void RemoveSession (uint64_t connID); @@ -131,6 +132,7 @@ namespace transport m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6; std::shared_ptr m_LastSession; bool m_IsPublished; // if we maintain introducers + bool m_IsSyncClockFromPeers; public: diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 205da574..f8c190c1 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -720,6 +720,7 @@ namespace transport } m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || encrypted payload from SessionCreated) for SessionConfirmed // payload + m_State = eSSU2SessionStateSessionCreatedReceived; HandlePayload (decryptedPayload.data (), decryptedPayload.size ()); m_Server.AddSession (shared_from_this ()); @@ -1320,13 +1321,7 @@ namespace transport { case eSSU2BlkDateTime: LogPrint (eLogDebug, "SSU2: Datetime"); - if (m_State == eSSU2SessionStateSessionRequestReceived) - { - auto ts = i2p::util::GetSecondsSinceEpoch (); - uint32_t signedOnTime = bufbe32toh (buf + offset); - if (signedOnTime < ts - SSU2_CLOCK_SKEW || signedOnTime > ts + SSU2_CLOCK_SKEW) - m_TerminationReason = eSSU2TerminationReasonClockSkew; - }; + HandleDateTime (buf + offset, size); break; case eSSU2BlkOptions: LogPrint (eLogDebug, "SSU2: Options"); @@ -1437,6 +1432,38 @@ namespace transport } } + void SSU2Session::HandleDateTime (const uint8_t * buf, size_t len) + { + int64_t offset = (int64_t)i2p::util::GetSecondsSinceEpoch () - (int64_t)bufbe32toh (buf); + switch (m_State) + { + case eSSU2SessionStateSessionRequestReceived: + if (std::abs (offset) > SSU2_CLOCK_SKEW) + m_TerminationReason = eSSU2TerminationReasonClockSkew; + break; + case eSSU2SessionStateSessionCreatedReceived: + if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetStatus () == eRouterStatusTesting) || + (m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusTesting)) + { + if (m_Server.IsSyncClockFromPeers ()) + { + if (std::abs (offset) > SSU2_CLOCK_THRESHOLD) + { + LogPrint (eLogWarning, "SSU2: Clock adjusted by ", -offset, " seconds"); + i2p::util::AdjustTimeOffset (-offset); + } + } + else if (std::abs (offset) > SSU2_CLOCK_SKEW) + { + LogPrint (eLogError, "SSU2: Clock skew detected ", offset, ". Check your clock"); + i2p::context.SetError (eRouterErrorClockSkew); + } + } + break; + default: ; + }; + } + void SSU2Session::HandleAck (const uint8_t * buf, size_t len) { if (m_State == eSSU2SessionStateSessionConfirmedSent) diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 9a9ac0d6..1730a939 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -27,6 +27,7 @@ namespace transport const int SSU2_CONNECT_TIMEOUT = 5; // 5 seconds const int SSU2_TERMINATION_TIMEOUT = 330; // 5.5 minutes const int SSU2_CLOCK_SKEW = 60; // in seconds + const int SSU2_CLOCK_THRESHOLD = 15; // in seconds, if more we should adjust const int SSU2_TOKEN_EXPIRATION_TIMEOUT = 9; // for Retry message, in seconds const int SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT = 52*60; // for next token block, in seconds const int SSU2_TOKEN_EXPIRATION_THRESHOLD = 2; // in seconds @@ -92,6 +93,7 @@ namespace transport eSSU2SessionStateSessionRequestSent, eSSU2SessionStateSessionRequestReceived, eSSU2SessionStateSessionCreatedSent, + eSSU2SessionStateSessionCreatedReceived, eSSU2SessionStateSessionConfirmedSent, eSSU2SessionStateEstablished, eSSU2SessionStateClosing, @@ -280,6 +282,7 @@ namespace transport void SendPathResponse (const uint8_t * data, size_t len); void HandlePayload (const uint8_t * buf, size_t len); + void HandleDateTime (const uint8_t * buf, size_t len); void HandleAck (const uint8_t * buf, size_t len); void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts); void HandleAddress (const uint8_t * buf, size_t len);