diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index d077644d..b3b3d60a 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -64,6 +64,8 @@ namespace i2p { i2p::config::Init(); i2p::config::ParseCmdline(argc, argv); + + std::string config; i2p::config::GetOption("conf", config); std::string datadir; i2p::config::GetOption("datadir", datadir); @@ -247,12 +249,17 @@ namespace i2p LogPrint(eLogInfo, "Daemon: using hidden mode"); i2p::data::netdb.SetHidden(true); } + return true; } bool Daemon_Singleton::start() { + i2p::log::Logger().Start(); + + i2p::util::SyncTimeWithNTP(); + LogPrint(eLogInfo, "Daemon: starting NetDB"); i2p::data::netdb.Start(); @@ -264,7 +271,12 @@ namespace i2p bool ntcp; i2p::config::GetOption("ntcp", ntcp); bool ssu; i2p::config::GetOption("ssu", ssu); - LogPrint(eLogInfo, "Daemon: starting Transports"); + + + LogPrint(eLogInfo, "Daemon: starting Transports"); + + + if(!ssu) LogPrint(eLogInfo, "Daemon: ssu disabled"); if(!ntcp) LogPrint(eLogInfo, "Daemon: ntcp disabled"); diff --git a/daemon/Daemon.h b/daemon/Daemon.h index 48301e73..873e395b 100644 --- a/daemon/Daemon.h +++ b/daemon/Daemon.h @@ -15,7 +15,7 @@ namespace util virtual bool init(int argc, char* argv[]); virtual bool start(); virtual bool stop(); - virtual void run () {}; + virtual void run () { }; bool isDaemon; bool running; diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index d9cc6dec..95f5c41c 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -230,6 +230,12 @@ namespace config { ("exploratory.inbound.quantity", value()->default_value(3), "Exploratory inbound tunnels quantity") ("exploratory.outbound.quantity", value()->default_value(3), "Exploratory outbound tunnels quantity") ; + options_description time("Time Options"); + time.add_options() + ("time.use_ntp", value()->default_value(false), "Use NTP") + ("time.correcting", value()->default_value(false), "EXPEREMENTAL: Try correcting with peer, unsecurity") + ("time.ntp_server", value()->default_value(offical_ntp_server), "NTP Server host") + ; m_OptionsDesc .add(general) @@ -248,6 +254,7 @@ namespace config { .add(trust) .add(websocket) .add(exploratory) + .add(time) ; } diff --git a/libi2pd/Config.h b/libi2pd/Config.h index 0bbcd5b1..9a462641 100644 --- a/libi2pd/Config.h +++ b/libi2pd/Config.h @@ -18,6 +18,12 @@ namespace i2p { namespace config { + + constexpr const char offical_ntp_server[] = "0.pool.ntp.org," + "1.pool.ntp.org," + "2.pool.ntp.org," + "3.pool.ntp.org"; + extern boost::program_options::variables_map m_Options; /** diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index b191cbf1..f32ddd5e 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -483,7 +483,7 @@ namespace client LogPrint (eLogDebug, "Destination: Publishing LeaseSet is pending"); return; } - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::seconds); if (ts < m_LastSubmissionTime + PUBLISH_MIN_INTERVAL) { LogPrint (eLogDebug, "Destination: Publishing LeaseSet is too fast. Wait for ", PUBLISH_MIN_INTERVAL, " seconds"); @@ -621,7 +621,7 @@ namespace client auto request = std::make_shared (m_Service); if (requestComplete) request->requestComplete.push_back (requestComplete); - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::seconds); auto ret = m_LeaseSetRequests.insert (std::pair >(dest,request)); if (ret.second) // inserted { @@ -701,7 +701,7 @@ namespace client if (it != m_LeaseSetRequests.end ()) { bool done = false; - uint64_t ts = i2p::util::GetSecondsSinceEpoch (); + int64_t ts = i2p::util::getTime (i2p::util::TimeType::seconds); if (ts < it->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT) { auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, it->second->excluded); diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 59089072..e9e0cca9 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -34,7 +34,7 @@ namespace garlic memcpy (m_SessionKey, sessionKey, 32); m_Encryption.SetKey (m_SessionKey); m_SessionTags.push_back (sessionTag); - m_SessionTags.back ().creationTime = i2p::util::GetSecondsSinceEpoch (); + m_SessionTags.back ().creationTime = i2p::util::getTime (i2p::util::TimeType::seconds) ; } GarlicRoutingSession::~GarlicRoutingSession () @@ -44,7 +44,7 @@ namespace garlic std::shared_ptr GarlicRoutingSession::GetSharedRoutingPath () { if (!m_SharedRoutingPath) return nullptr; - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; if (m_SharedRoutingPath->numTimesUsed >= ROUTING_PATH_MAX_NUM_TIMES_USED || !m_SharedRoutingPath->outboundTunnel->IsEstablished () || ts*1000LL > m_SharedRoutingPath->remoteLease->endDate || @@ -58,7 +58,7 @@ namespace garlic { if (path && path->outboundTunnel && path->remoteLease) { - path->updateTime = i2p::util::GetSecondsSinceEpoch (); + path->updateTime = i2p::util::getTime (i2p::util::TimeType::seconds) ; path->numTimesUsed = 0; } else @@ -69,7 +69,7 @@ namespace garlic GarlicRoutingSession::UnconfirmedTags * GarlicRoutingSession::GenerateSessionTags () { auto tags = new UnconfirmedTags (m_NumTags); - tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch (); + tags->tagsCreationTime = i2p::util::getTime (i2p::util::TimeType::seconds) ; for (int i = 0; i < m_NumTags; i++) { RAND_bytes (tags->sessionTags[i], 32); @@ -93,7 +93,7 @@ namespace garlic void GarlicRoutingSession::TagsConfirmed (uint32_t msgID) { - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; auto it = m_UnconfirmedTagsMsgs.find (msgID); if (it != m_UnconfirmedTagsMsgs.end ()) { @@ -109,7 +109,7 @@ namespace garlic bool GarlicRoutingSession::CleanupExpiredTags () { - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; for (auto it = m_SessionTags.begin (); it != m_SessionTags.end ();) { if (ts >= it->creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) @@ -130,7 +130,7 @@ namespace garlic bool GarlicRoutingSession::CleanupUnconfirmedTags () { bool ret = false; - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; // delete expired unconfirmed tags for (auto it = m_UnconfirmedTagsMsgs.begin (); it != m_UnconfirmedTagsMsgs.end ();) { @@ -159,7 +159,7 @@ namespace garlic SessionTag tag; if (m_NumTags > 0) { - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; while (!m_SessionTags.empty ()) { if (ts < m_SessionTags.front ().creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) @@ -169,8 +169,10 @@ namespace garlic tagFound = true; break; } - else + else{ m_SessionTags.pop_front (); // remove expired tag + LogPrint(eLogInfo, "Garlic: Remove expired tag"); + } } } // create message @@ -247,7 +249,7 @@ namespace garlic size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, std::shared_ptr msg, UnconfirmedTags * newTags) { - uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); + uint64_t ts = i2p::util::getTime (i2p::util::TimeType::milliseconds) ; uint32_t msgID; RAND_bytes ((uint8_t *)&msgID, 4); size_t size = 0; @@ -315,7 +317,7 @@ namespace garlic size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, std::shared_ptr msg, bool isDestination) { - uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec + uint64_t ts = i2p::util::getTime (i2p::util::TimeType::milliseconds) + 8000; // 8 sec size_t size = 0; if (isDestination) { @@ -373,7 +375,7 @@ namespace garlic memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); size += msg->GetLength (); // fill clove - uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec + uint64_t ts = i2p::util::getTime (i2p::util::TimeType::milliseconds) + 8000; // 8 sec uint32_t cloveID; RAND_bytes ((uint8_t *)&cloveID, 4); htobe32buf (buf + size, cloveID); // CloveID @@ -412,7 +414,7 @@ namespace garlic { if (key) { - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; m_Tags[SessionTag(tag, ts)] = std::make_shared(key); } } @@ -480,7 +482,7 @@ namespace garlic LogPrint (eLogError, "Garlic: Tag count ", tagCount, " exceeds length ", len); return ; } - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; for (int i = 0; i < tagCount; i++) m_Tags[SessionTag(buf + i*32, ts)] = decryption; } @@ -658,7 +660,7 @@ namespace garlic void GarlicDestination::CleanupExpiredTags () { // incoming - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; int numExpiredTags = 0; for (auto it = m_Tags.begin (); it != m_Tags.end ();) { @@ -757,7 +759,7 @@ namespace garlic std::string ident = GetIdentHash().ToBase32(); std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags")); std::ofstream f (path, std::ofstream::binary | std::ofstream::out | std::ofstream::trunc); - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; // 4 bytes timestamp, 32 bytes tag, 32 bytes key for (auto it: m_Tags) { @@ -774,7 +776,7 @@ namespace garlic { std::string ident = GetIdentHash().ToBase32(); std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags")); - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; if (ts < i2p::fs::GetLastUpdateTime (path) + INCOMING_TAGS_EXPIRATION_TIMEOUT) { // might contain non-expired tags @@ -816,7 +818,7 @@ namespace garlic { std::vector files; i2p::fs::ReadDir (i2p::fs::DataDirPath("tags"), files); - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; for (auto it: files) if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT) i2p::fs::Remove (it); diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 9bb7dfd1..0685279e 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -44,7 +44,7 @@ namespace i2p SetTypeID (msgType); if (!replyMsgID) RAND_bytes ((uint8_t *)&replyMsgID, 4); SetMsgID (replyMsgID); - SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT); + SetExpiration (i2p::util::getTime (i2p::util::TimeType::milliseconds) + I2NP_MESSAGE_EXPIRATION_TIMEOUT); UpdateSize (); UpdateChks (); } @@ -54,13 +54,14 @@ namespace i2p uint32_t msgID; RAND_bytes ((uint8_t *)&msgID, 4); SetMsgID (msgID); - SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT); + SetExpiration (i2p::util::getTime (i2p::util::TimeType::milliseconds) + I2NP_MESSAGE_EXPIRATION_TIMEOUT); } bool I2NPMessage::IsExpired () const { - auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto exp = GetExpiration (); + auto ts = i2p::util::getTime (i2p::util::TimeType::milliseconds) ; + return (ts > exp + I2NP_MESSAGE_CLOCK_SKEW) || (ts < exp - 3*I2NP_MESSAGE_CLOCK_SKEW); // check if expired or too far in future } @@ -103,7 +104,7 @@ namespace i2p if (msgID) { htobe32buf (buf + DELIVERY_STATUS_MSGID_OFFSET, msgID); - htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, i2p::util::GetMillisecondsSinceEpoch ()); + htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, i2p::util::getTime (i2p::util::TimeType::milliseconds) ); } else // for SSU establishment { diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index f2355930..aa083ef3 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -73,7 +73,7 @@ namespace data // process leases m_ExpirationTime = 0; - auto ts = i2p::util::GetMillisecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::milliseconds); const uint8_t * leases = m_Buffer + size; for (int i = 0; i < num; i++) { @@ -165,7 +165,7 @@ namespace data bool LeaseSet::ExpiresSoon(const uint64_t dlt, const uint64_t fudge) const { - auto now = i2p::util::GetMillisecondsSinceEpoch (); + auto now = i2p::util::getTime (i2p::util::TimeType::milliseconds); if (fudge) now += rand() % fudge; if (now >= m_ExpirationTime) return true; return m_ExpirationTime - now <= dlt; @@ -178,7 +178,7 @@ namespace data const std::vector > LeaseSet::GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold) const { - auto ts = i2p::util::GetMillisecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::milliseconds); std::vector > leases; for (const auto& it: m_Leases) { @@ -195,7 +195,7 @@ namespace data bool LeaseSet::HasExpiredLeases () const { - auto ts = i2p::util::GetMillisecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::milliseconds); for (const auto& it: m_Leases) if (ts >= it->endDate) return true; return false; @@ -204,7 +204,7 @@ namespace data bool LeaseSet::IsExpired () const { if (m_StoreLeases && IsEmpty ()) return true; - auto ts = i2p::util::GetMillisecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::milliseconds); return ts > m_ExpirationTime; } @@ -234,7 +234,7 @@ namespace data offset++; // leases m_Leases = m_Buffer + offset; - auto currentTime = i2p::util::GetMillisecondsSinceEpoch (); + auto currentTime = i2p::util::getTime (i2p::util::TimeType::milliseconds); for (int i = 0; i < num; i++) { memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32); @@ -262,7 +262,7 @@ namespace data bool LocalLeaseSet::IsExpired () const { - auto ts = i2p::util::GetMillisecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::milliseconds); return ts > m_ExpirationTime; } diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index fa24df2f..94d3407c 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -28,7 +28,7 @@ namespace data bool isUpdated; // trasient /* return true if this lease expires within t millisecond + fudge factor */ bool ExpiresWithin( const uint64_t t, const uint64_t fudge = 1000 ) const { - auto expire = i2p::util::GetMillisecondsSinceEpoch (); + auto expire = i2p::util::getTime (i2p::util::TimeType::milliseconds); if(fudge) expire += rand() % fudge; if (endDate < expire) return true; return (endDate - expire) < t; diff --git a/libi2pd/NTCPSession.cpp b/libi2pd/NTCPSession.cpp index e3d6c004..8e162088 100644 --- a/libi2pd/NTCPSession.cpp +++ b/libi2pd/NTCPSession.cpp @@ -128,7 +128,7 @@ namespace transport void NTCPSession::ServerLogin () { - m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); + m_LastActivityTimestamp = i2p::util::getTime (i2p::util::TimeType::seconds); // receive Phase1 boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase1, sizeof (NTCPPhase1)), boost::asio::transfer_all (), std::bind(&NTCPSession::HandlePhase1Received, shared_from_this (), @@ -195,7 +195,7 @@ namespace transport memcpy (xy, m_Establisher->phase1.pubKey, 256); memcpy (xy + 256, y, 256); SHA256(xy, 512, m_Establisher->phase2.encrypted.hxy); - uint32_t tsB = htobe32 (i2p::util::GetSecondsSinceEpoch ()); + uint32_t tsB = htobe32 (i2p::util::getTime (i2p::util::TimeType::seconds) ); memcpy (m_Establisher->phase2.encrypted.timestamp, &tsB, 4); RAND_bytes (m_Establisher->phase2.encrypted.filler, 12); @@ -279,7 +279,7 @@ namespace transport htobe16buf (buf, keys.GetPublic ()->GetFullLen ()); buf += 2; buf += i2p::context.GetIdentity ()->ToBuffer (buf, NTCP_BUFFER_SIZE); - uint32_t tsA = htobe32 (i2p::util::GetSecondsSinceEpoch ()); + uint32_t tsA = htobe32 (i2p::util::getTime (i2p::util::TimeType::seconds) ); htobuf32(buf,tsA); buf += 4; size_t signatureLen = keys.GetPublic ()->GetSignatureLen (); @@ -389,13 +389,15 @@ namespace transport buf += paddingLen; // check timestamp - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; uint32_t tsA1 = be32toh (tsA); if (tsA1 < ts - NTCP_CLOCK_SKEW || tsA1 > ts + NTCP_CLOCK_SKEW) { - LogPrint (eLogError, "NTCP: Phase3 time difference ", ts - tsA1, " exceeds clock skew"); - Terminate (); - return; + if( !i2p::util::timeCorrecting(tsA1, ts, NTCP_CLOCK_SKEW, "NTCP: Phase3 time difference ") ){ + LogPrint (eLogError, "NTCP: Phase3 time difference ", ts - tsA1, " exceeds clock skew"); + Terminate (); + return; + } } // check signature @@ -460,8 +462,10 @@ namespace transport if (ecode) { LogPrint (eLogError, "NTCP: Phase 4 read error: ", ecode.message (), ". Check your clock"); + if (ecode != boost::asio::error::operation_aborted) { + LogPrint(eLogError, "NTCP: Phase 4 read error: ", "Close router"); // this router doesn't like us i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); Terminate (); @@ -473,12 +477,16 @@ namespace transport // check timestamp uint32_t tsB = bufbe32toh (m_Establisher->phase2.encrypted.timestamp); - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; if (tsB < ts - NTCP_CLOCK_SKEW || tsB > ts + NTCP_CLOCK_SKEW) { - LogPrint (eLogError, "NTCP: Phase4 time difference ", ts - tsB, " exceeds clock skew"); - Terminate (); - return; + + if( !i2p::util::timeCorrecting(tsB, ts, NTCP_CLOCK_SKEW, "NTCP: Phase3 time difference ") ) + { + LogPrint (eLogError, "NTCP: Phase4 time difference ", ts - tsB, " exceeds clock skew"); + Terminate (); + return; + } } // verify signature @@ -589,7 +597,7 @@ namespace transport } m_Handler.Flush (); - m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); + m_LastActivityTimestamp = i2p::util::getTime (i2p::util::TimeType::seconds); Receive (); } } @@ -620,7 +628,7 @@ namespace transport else { // timestamp - int diff = (int)bufbe32toh (buf + 2) - (int)i2p::util::GetSecondsSinceEpoch (); + int diff = (int)bufbe32toh (buf + 2) - (int)i2p::util::getTime (i2p::util::TimeType::seconds) ; LogPrint (eLogInfo, "NTCP: Timestamp. Time difference ", diff, " seconds"); return true; } @@ -638,7 +646,7 @@ namespace transport htobe32buf (checksum, adler32 (adler32 (0, Z_NULL, 0), m_NextMessage->GetBuffer () - 2, m_NextMessageOffset - 4)); if (!memcmp (m_NextMessage->GetBuffer () - 2 + m_NextMessageOffset - 4, checksum, 4)) { - if (!m_NextMessage->IsExpired ()) + if (!m_NextMessage->IsExpired ()) // TODO: look to { #ifdef WITH_EVENTS QueueIntEvent("transport.recvmsg", GetIdentHashBase64(), 1); @@ -682,7 +690,7 @@ namespace transport sendBuffer = m_TimeSyncBuffer; len = 4; htobuf16(sendBuffer, 0); - htobe32buf (sendBuffer + 2, i2p::util::GetSecondsSinceEpoch ()); + htobe32buf (sendBuffer + 2, i2p::util::getTime (i2p::util::TimeType::seconds) ); } int rem = (len + 6) & 0x0F; // %16 int padding = 0; @@ -722,7 +730,7 @@ namespace transport } else { - m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); + m_LastActivityTimestamp = i2p::util::getTime (i2p::util::TimeType::seconds); m_NumSentBytes += bytes_transferred; i2p::transport::transports.UpdateSentBytes (bytes_transferred); if (!m_SendQueue.empty()) @@ -1271,7 +1279,7 @@ namespace transport { if (ecode != boost::asio::error::operation_aborted) { - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::seconds); // established for (auto& it: m_NTCPSessions) if (it.second->IsTerminationTimeoutExpired (ts)) diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index f1853124..0e4beab6 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -20,7 +20,7 @@ namespace data msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers); if(router) m_ExcludedPeers.insert (router->GetIdentHash ()); - m_CreationTime = i2p::util::GetSecondsSinceEpoch (); + m_CreationTime = i2p::util::getTime (i2p::util::TimeType::seconds); return msg; } @@ -29,7 +29,7 @@ namespace data auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers); m_ExcludedPeers.insert (floodfill); - m_CreationTime = i2p::util::GetSecondsSinceEpoch (); + m_CreationTime = i2p::util::getTime (i2p::util::TimeType::seconds); return msg; } @@ -111,7 +111,7 @@ namespace data void NetDbRequests::ManageRequests () { - uint64_t ts = i2p::util::GetSecondsSinceEpoch (); + uint64_t ts = i2p::util::getTime (i2p::util::TimeType::seconds); std::unique_lock l(m_RequestedDestinationsMutex); for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();) { diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 2a8cd2d5..8058672a 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -32,7 +32,7 @@ namespace transport auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false); if (address) m_IntroKey = address->ssu->key; } - m_CreationTime = i2p::util::GetSecondsSinceEpoch (); + m_CreationTime =i2p::util::getTime (i2p::util::TimeType::seconds) ; } SSUSession::~SSUSession () @@ -98,7 +98,7 @@ namespace transport { if (!len) return; // ignore zero-length packets if (m_State == eSessionStateEstablished) - m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); + m_LastActivityTimestamp =i2p::util::getTime (i2p::util::TimeType::seconds) ; if (m_IsSessionKey && Validate (buf, len, m_MacKey)) // try session key first DecryptSessionKey (buf, len); @@ -276,13 +276,13 @@ namespace transport payload += 4; // relayTag if (i2p::context.GetStatus () == eRouterStatusTesting) { - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; uint32_t signedOnTime = bufbe32toh(payload); if (signedOnTime < ts - SSU_CLOCK_SKEW || signedOnTime > ts + SSU_CLOCK_SKEW) { - LogPrint (eLogError, "SSU: clock skew detected ", (int)ts - signedOnTime, ". Check your clock"); - i2p::context.SetError (eRouterErrorClockSkew); + i2p::util::timeCorrecting(signedOnTime, ts, SSU_CLOCK_SKEW, "SSU: clock skew detected "); } + } payload += 4; // signed on time // decrypt signature @@ -324,7 +324,7 @@ namespace transport SetRemoteIdentity (existing ? existing->GetRouterIdentity () : identity); m_Data.UpdatePacketSize (m_RemoteIdentity->GetIdentHash ()); payload += identitySize; // identity - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::seconds) ; uint32_t signedOnTime = bufbe32toh(payload); if (signedOnTime < ts - SSU_CLOCK_SKEW || signedOnTime > ts + SSU_CLOCK_SKEW) { @@ -469,7 +469,7 @@ namespace transport } htobe32buf (payload, m_SentRelayTag); payload += 4; // relay tag - htobe32buf (payload, i2p::util::GetSecondsSinceEpoch ()); // signed on time + htobe32buf (payload,i2p::util::getTime (i2p::util::TimeType::seconds) ); // signed on time payload += 4; s.Insert (payload - 8, 4); // relayTag // we have to store this signed data for session confirmed @@ -510,7 +510,7 @@ namespace transport payload += 2; // cursize i2p::context.GetIdentity ()->ToBuffer (payload, identLen); payload += identLen; - uint32_t signedOnTime = i2p::util::GetSecondsSinceEpoch (); + uint32_t signedOnTime =i2p::util::getTime (i2p::util::TimeType::seconds) ; htobe32buf (payload, signedOnTime); // signed on time payload += 4; auto signatureLen = i2p::context.GetIdentity ()->GetSignatureLen (); @@ -721,7 +721,7 @@ namespace transport SSUHeader * header = (SSUHeader *)buf; memcpy (header->iv, iv, 16); header->flag = flag | (payloadType << 4); // MSB is 0 - htobe32buf (header->time, i2p::util::GetSecondsSinceEpoch ()); + htobe32buf (header->time,i2p::util::getTime (i2p::util::TimeType::seconds) ); uint8_t * encrypted = &header->flag; uint16_t encryptedLen = len - (encrypted - buf); i2p::crypto::CBCEncryption encryption; @@ -745,7 +745,7 @@ namespace transport RAND_bytes (header->iv, 16); // random iv m_SessionKeyEncryption.SetIV (header->iv); header->flag = payloadType << 4; // MSB is 0 - htobe32buf (header->time, i2p::util::GetSecondsSinceEpoch ()); + htobe32buf (header->time,i2p::util::getTime (i2p::util::TimeType::seconds) ); uint8_t * encrypted = &header->flag; uint16_t encryptedLen = len - (encrypted - buf); m_SessionKeyEncryption.Encrypt (encrypted, encryptedLen, encrypted); @@ -907,7 +907,7 @@ namespace transport SendPeerTest (); if (m_SentRelayTag) m_Server.AddRelay (m_SentRelayTag, shared_from_this ()); - m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); + m_LastActivityTimestamp = i2p::util::getTime (i2p::util::TimeType::seconds) ; } void SSUSession::Failed () @@ -1149,7 +1149,7 @@ namespace transport FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48); Send (buf, 48); LogPrint (eLogDebug, "SSU: keep-alive sent"); - m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); + m_LastActivityTimestamp =i2p::util::getTime (i2p::util::TimeType::seconds) ; } } diff --git a/libi2pd/Timestamp.cpp b/libi2pd/Timestamp.cpp index 9e9b4e63..8262287a 100644 --- a/libi2pd/Timestamp.cpp +++ b/libi2pd/Timestamp.cpp @@ -1,9 +1,13 @@ #include #include #include +#include + #include "Log.h" #include "I2PEndian.h" #include "Timestamp.h" +#include"RouterContext.h" + #ifdef WIN32 #ifndef _WIN64 @@ -15,51 +19,93 @@ namespace i2p { namespace util { - static int64_t g_TimeOffset = 0; // in seconds + int64_t g_TimeOffset; + static inline void setTimeOffset(int64_t ts){g_TimeOffset=ts;} + - void SyncTimeWithNTP (const std::string& address) + + bool timeCorrecting(uint32_t signedOnTime, uint32_t ts, uint32_t skew, const char * ErrorMsg){ + + bool Time_Correcting; i2p::config::GetOption("time.correcting", Time_Correcting); + + if( !Time_Correcting ){ + LogPrint (eLogError, ErrorMsg, (int)ts - signedOnTime, ". Check your clock"); + i2p::context.SetError (eRouterErrorClockSkew); + return false; + } + + if (signedOnTime > 2208988800U) signedOnTime -= 2208988800U; // 1/1/1970 from 1/1/1900 + + LogPrint (eLogWarning, "I2Pd Time correcting: timeCorrecting "); + i2p::util::setTimeOffset( signedOnTime < ts - skew ? -signedOnTime : signedOnTime ); + return true; + } + + + //TODO: ...Syncing with option + + bool SyncTimeWithNTP (void) { - boost::asio::io_service service; - boost::asio::ip::udp::resolver::query query (boost::asio::ip::udp::v4 (), address, "ntp"); - boost::system::error_code ec; - auto it = boost::asio::ip::udp::resolver (service).resolve (query, ec); - if (!ec && it != boost::asio::ip::udp::resolver::iterator()) - { - auto ep = (*it).endpoint (); // take first one - boost::asio::ip::udp::socket socket (service); - socket.open (boost::asio::ip::udp::v4 (), ec); - if (!ec) + + bool UseNTP; i2p::config::GetOption("time.use_ntp", UseNTP); + if(!UseNTP) return false; + + std::string address; i2p::config::GetOption("time.ntp_server", address); + + std::vector addresses; + boost::split(addresses, address, boost::is_any_of(",")); + + for ( auto addr : addresses ){ + LogPrint (eLogInfo, "I2Pd Time Correcting: SyncingWithNTP with server ", addr); + boost::asio::io_service service; + boost::asio::ip::udp::resolver::query query (boost::asio::ip::udp::v4 (), addr, "ntp"); + boost::system::error_code ec; + auto it = boost::asio::ip::udp::resolver (service).resolve (query, ec); + if (!ec && it != boost::asio::ip::udp::resolver::iterator()) { - uint8_t buf[48];// 48 bytes NTP request/response - memset (buf, 0, 48); - htobe32buf (buf, (3 << 27) | (3 << 24)); // RFC 4330 - size_t len = 0; - try + auto ep = (*it).endpoint (); // take first one + boost::asio::ip::udp::socket socket (service); + socket.open (boost::asio::ip::udp::v4 (), ec); + if (!ec) { - socket.send_to (boost::asio::buffer (buf, 48), ep); - int i = 0; - while (!socket.available() && i < 10) // 10 seconds max + uint8_t buf[48];// 48 bytes NTP request/response + memset (buf, 0, 48); + htobe32buf (buf, (3 << 27) | (3 << 24)); // RFC 4330 + size_t len = 0; + try { - std::this_thread::sleep_for (std::chrono::seconds(1)); - i++; - } - if (socket.available ()) - len = socket.receive_from (boost::asio::buffer (buf, 48), ep); - } - catch (std::exception& e) - { - LogPrint (eLogError, "NTP error: ", e.what ()); - } - if (len >= 8) - { - auto ourTs = GetSecondsSinceEpoch (); - uint32_t ts = bufbe32toh (buf + 32); - if (ts > 2208988800U) ts -= 2208988800U; // 1/1/1970 from 1/1/1900 - g_TimeOffset = ts - ourTs; - LogPrint (eLogInfo, address, " time offset from system time is ", g_TimeOffset, " seconds"); + socket.send_to (boost::asio::buffer (buf, 48), ep); + int i = 0; + while (!socket.available() && i < NTPMaxTimeConnecting) // 10 seconds max + { + std::this_thread::sleep_for (std::chrono::seconds(1)); + i++; + } + if( i == NTPMaxTimeConnecting ) throw( std::runtime_error("timeout" ) ); + if (socket.available ()) + len = socket.receive_from (boost::asio::buffer (buf, 48), ep); + if(len < 8) throw( std::runtime_error("len of answer not equal 8") ); + + auto ourTs = GetSecondsSinceEpoch (); + uint32_t ts = bufbe32toh (buf + 32); + LogPrint (eLogDebug, "I2Pd Time Correcting: SyncingWithNTP ",ourTs, " < our not our > ", ts); + if (ts > 2208988800U) ts -= 2208988800U; // 1/1/1970 from 1/1/1900 + + setTimeOffset( ts - ourTs ); + + LogPrint (eLogDebug, "I2Pd Time Correcting: ", addr, " time offset from system time is ", g_TimeOffset, " seconds"); + break; + + }catch (std::exception& e) + { + LogPrint (eLogError, "NTP error: ", e.what ()); + } + } } + } + return true; } } } diff --git a/libi2pd/Timestamp.h b/libi2pd/Timestamp.h index cddc6518..7afa3479 100644 --- a/libi2pd/Timestamp.h +++ b/libi2pd/Timestamp.h @@ -3,30 +3,83 @@ #include #include +#include"Config.h" +#include "Log.h" namespace i2p { -namespace util -{ - inline uint64_t GetMillisecondsSinceEpoch () + namespace util { - return std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()).count (); - } + constexpr char NTPMaxTimeConnecting = 15; + extern int64_t g_TimeOffset; // in seconds - inline uint32_t GetHoursSinceEpoch () - { - return std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()).count (); - } + enum class TimeType{ + milliseconds, seconds, hours + }; - inline uint64_t GetSecondsSinceEpoch () - { - return std::chrono::duration_cast( + template inline uint64_t getTime(void) + { + return std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()).count (); + } + + template auto getTime(TimeType tt) -> decltype(getTime()){ + + + LogPrint (eLogDebug, "I2Pd Time Correcting: offset = ", g_TimeOffset ); + + + + bool Time_Correcting, Time_UseNTP; + i2p::config::GetOption("time.correcting", Time_Correcting); + i2p::config::GetOption("time.use_ntp", Time_UseNTP); + if(Time_Correcting || Time_UseNTP) + LogPrint (eLogDebug, "I2Pd Time Correcting: Return time with offset ", getTime() + g_TimeOffset ); + else + LogPrint(eLogDebug, "I2Pd Time Correcting: return real time"); + if(Time_Correcting || Time_UseNTP){ + auto tmpTime = getTime() ; + switch(tt){ + case TimeType::milliseconds: + return tmpTime+g_TimeOffset*1000; + case TimeType::seconds: + return tmpTime+g_TimeOffset; + break; + case TimeType::hours: + if(tmpTime) + return tmpTime + g_TimeOffset/120; + break; + } + } + return getTime(); + + } + + + + + bool timeCorrecting(uint32_t signedOnTime, uint32_t ts, uint32_t skew, const char * ErrorMsg); + bool SyncTimeWithNTP (void); + + + inline uint64_t GetSecondsSinceEpoch () + { + return getTime(); + } + + inline uint64_t GetMillisecondsSinceEpoch () + { + return getTime(); + } + + inline uint32_t GetHoursSinceEpoch () + { + return getTime(); + } + + } } -} #endif diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 361d9f94..a6f20a2a 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -345,7 +345,7 @@ namespace client auto l = version.length () + 1 + 8; uint8_t * payload = new uint8_t[l]; // set date - auto ts = i2p::util::GetMillisecondsSinceEpoch (); + auto ts = i2p::util::getTime (i2p::util::TimeType::milliseconds); htobe64buf (payload, ts); // echo vesrion back PutString (payload + 8, l - 8, version); diff --git a/libi2pd_client/I2PService.cpp b/libi2pd_client/I2PService.cpp index 21e1fdfa..a2d10297 100644 --- a/libi2pd_client/I2PService.cpp +++ b/libi2pd_client/I2PService.cpp @@ -60,7 +60,7 @@ namespace client void I2PService::AddReadyCallback(ReadyCallback cb) { - uint32_t now = i2p::util::GetSecondsSinceEpoch(); + uint32_t now = i2p::util::getTime (i2p::util::TimeType::seconds); uint32_t tm = now + m_ConnectTimeout; LogPrint(eLogDebug, "I2PService::AddReadyCallback() ", tm, " ", now); m_ReadyCallbacks.push_back({cb, tm}); @@ -83,7 +83,7 @@ namespace client else if(!m_LocalDestination->IsReady()) { // expire timed out requests - uint32_t now = i2p::util::GetSecondsSinceEpoch (); + uint32_t now = i2p::util::getTime (i2p::util::TimeType::seconds); auto itr = m_ReadyCallbacks.begin(); while(itr != m_ReadyCallbacks.end()) { diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 975cc4ce..19c299ea 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -604,12 +604,12 @@ namespace client std::lock_guard lock(m_SessionsMutex); auto session = ObtainUDPSession(from, toPort, fromPort); session->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint); - session->LastActivity = i2p::util::GetMillisecondsSinceEpoch(); + session->LastActivity = i2p::util::getTime (i2p::util::TimeType::milliseconds); } void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) { std::lock_guard lock(m_SessionsMutex); - uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); + uint64_t now = i2p::util::getTime (i2p::util::TimeType::milliseconds); auto itr = m_Sessions.begin(); while(itr != m_Sessions.end()) { if(now - (*itr)->LastActivity >= delta ) @@ -621,7 +621,7 @@ namespace client void I2PUDPClientTunnel::ExpireStale(const uint64_t delta) { std::lock_guard lock(m_SessionsMutex); - uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); + uint64_t now = i2p::util::getTime (i2p::util::TimeType::milliseconds); std::vector removePorts; for (const auto & s : m_Sessions) { if (now - s.second.second >= delta) @@ -666,7 +666,7 @@ namespace client m_Destination(localDestination->GetDatagramDestination()), IPSocket(localDestination->GetService(), localEndpoint), SendEndpoint(endpoint), - LastActivity(i2p::util::GetMillisecondsSinceEpoch()), + LastActivity(i2p::util::getTime (i2p::util::TimeType::milliseconds)), LocalPort(ourPort), RemotePort(theirPort) { @@ -685,7 +685,7 @@ namespace client if(!ecode) { LogPrint(eLogDebug, "UDPSession: forward ", len, "B from ", FromEndpoint); - LastActivity = i2p::util::GetMillisecondsSinceEpoch(); + LastActivity = i2p::util::getTime (i2p::util::TimeType::milliseconds); m_Destination->SendDatagramTo(m_Buffer, len, Identity, LocalPort, RemotePort); Receive(); } else { @@ -795,7 +795,7 @@ namespace client LogPrint(eLogDebug, "UDP Client: send ", transferred, " to ", m_RemoteIdent->ToBase32(), ":", RemotePort); m_LocalDest->GetDatagramDestination()->SendDatagramTo(m_RecvBuff, transferred, *m_RemoteIdent, remotePort, RemotePort); // mark convo as active - m_Sessions[remotePort].second = i2p::util::GetMillisecondsSinceEpoch(); + m_Sessions[remotePort].second = i2p::util::getTime (i2p::util::TimeType::milliseconds); RecvFromLocal(); } @@ -837,7 +837,7 @@ namespace client LogPrint(eLogDebug, "UDP Client: got ", len, "B from ", from.GetIdentHash().ToBase32()); m_LocalSocket.send_to(boost::asio::buffer(buf, len), itr->second.first); // mark convo as active - itr->second.second = i2p::util::GetMillisecondsSinceEpoch(); + itr->second.second = i2p::util::getTime (i2p::util::TimeType::milliseconds); } } else