You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

timedata.cpp 3.8KB

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