Line data Source code
1 : // Copyright (c) 2014-2020 The Bitcoin Core developers 2 : // Distributed under the MIT software license, see the accompanying 3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 : 5 : #if defined(HAVE_CONFIG_H) 6 : #include <config/bitcoin-config.h> 7 : #endif 8 : 9 : #include <timedata.h> 10 : 11 : #include <netaddress.h> 12 : #include <node/ui_interface.h> 13 : #include <sync.h> 14 : #include <util/system.h> 15 : #include <util/translation.h> 16 : #include <warnings.h> 17 : 18 640 : static Mutex g_timeoffset_mutex; 19 : static int64_t nTimeOffset GUARDED_BY(g_timeoffset_mutex) = 0; 20 : 21 : /** 22 : * "Never go to sea with two chronometers; take one or three." 23 : * Our three time sources are: 24 : * - System clock 25 : * - Median of other nodes clocks 26 : * - The user (asking the user to fix the system clock if the first two disagree) 27 : */ 28 1466674 : int64_t GetTimeOffset() 29 : { 30 1466674 : LOCK(g_timeoffset_mutex); 31 1466674 : return nTimeOffset; 32 1466674 : } 33 : 34 1466627 : int64_t GetAdjustedTime() 35 : { 36 1466627 : return GetTime() + GetTimeOffset(); 37 : } 38 : 39 102 : static int64_t abs64(int64_t n) 40 : { 41 102 : return (n >= 0 ? n : -n); 42 : } 43 : 44 : #define BITCOIN_TIMEDATA_MAX_SAMPLES 200 45 : 46 898 : void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) 47 : { 48 898 : LOCK(g_timeoffset_mutex); 49 : // Ignore duplicates 50 898 : static std::set<CNetAddr> setKnown; 51 898 : if (setKnown.size() == BITCOIN_TIMEDATA_MAX_SAMPLES) 52 0 : return; 53 898 : if (!setKnown.insert(ip).second) 54 398 : return; 55 : 56 : // Add data 57 500 : static CMedianFilter<int64_t> vTimeOffsets(BITCOIN_TIMEDATA_MAX_SAMPLES, 0); 58 500 : vTimeOffsets.input(nOffsetSample); 59 500 : LogPrint(BCLog::NET, "added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample / 60); 60 : 61 : // There is a known issue here (see issue #4521): 62 : // 63 : // - The structure vTimeOffsets contains up to 200 elements, after which 64 : // any new element added to it will not increase its size, replacing the 65 : // oldest element. 66 : // 67 : // - The condition to update nTimeOffset includes checking whether the 68 : // number of elements in vTimeOffsets is odd, which will never happen after 69 : // there are 200 elements. 70 : // 71 : // But in this case the 'bug' is protective against some attacks, and may 72 : // actually explain why we've never seen attacks which manipulate the 73 : // clock offset. 74 : // 75 : // So we should hold off on fixing this and clean it up as part of 76 : // a timing cleanup that strengthens it in a number of other ways. 77 : // 78 500 : if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) { 79 98 : int64_t nMedian = vTimeOffsets.median(); 80 98 : std::vector<int64_t> vSorted = vTimeOffsets.sorted(); 81 : // Only let other nodes change our time by so much 82 98 : if (abs64(nMedian) <= std::max<int64_t>(0, gArgs.GetArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT))) { 83 96 : nTimeOffset = nMedian; 84 96 : } else { 85 2 : nTimeOffset = 0; 86 : 87 : static bool fDone; 88 2 : if (!fDone) { 89 : // If nobody has a time different than ours but within 5 minutes of ours, give a warning 90 : bool fMatch = false; 91 6 : for (const int64_t nOffset : vSorted) { 92 5 : if (nOffset != 0 && abs64(nOffset) < 5 * 60) fMatch = true; 93 : } 94 : 95 1 : if (!fMatch) { 96 1 : fDone = true; 97 1 : bilingual_str strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), PACKAGE_NAME); 98 1 : SetMiscWarning(strMessage); 99 1 : uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING); 100 1 : } 101 1 : } 102 : } 103 : 104 98 : if (LogAcceptCategory(BCLog::NET)) { 105 10094 : for (const int64_t n : vSorted) { 106 9996 : LogPrint(BCLog::NET, "%+d ", n); /* Continued */ 107 9996 : } 108 98 : LogPrint(BCLog::NET, "| "); /* Continued */ 109 98 : LogPrint(BCLog::NET, "nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset / 60); 110 : } 111 98 : } 112 898 : }