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.

alert.cpp 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Copyright (c) 2010 Satoshi Nakamoto
  2. // Copyright (c) 2009-2014 The Bitcoin developers
  3. // Distributed under the MIT/X11 software license, see the accompanying
  4. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  5. #include "alert.h"
  6. #include "chainparams.h"
  7. #include "key.h"
  8. #include "net.h"
  9. #include "ui_interface.h"
  10. #include "util.h"
  11. #include <stdint.h>
  12. #include <algorithm>
  13. #include <map>
  14. #include <boost/algorithm/string/classification.hpp>
  15. #include <boost/algorithm/string/replace.hpp>
  16. #include <boost/foreach.hpp>
  17. using namespace std;
  18. map<uint256, CAlert> mapAlerts;
  19. CCriticalSection cs_mapAlerts;
  20. void CUnsignedAlert::SetNull()
  21. {
  22. nVersion = 1;
  23. nRelayUntil = 0;
  24. nExpiration = 0;
  25. nID = 0;
  26. nCancel = 0;
  27. setCancel.clear();
  28. nMinVer = 0;
  29. nMaxVer = 0;
  30. setSubVer.clear();
  31. nPriority = 0;
  32. strComment.clear();
  33. strStatusBar.clear();
  34. strReserved.clear();
  35. }
  36. std::string CUnsignedAlert::ToString() const
  37. {
  38. std::string strSetCancel;
  39. BOOST_FOREACH(int n, setCancel)
  40. strSetCancel += strprintf("%d ", n);
  41. std::string strSetSubVer;
  42. BOOST_FOREACH(std::string str, setSubVer)
  43. strSetSubVer += "\"" + str + "\" ";
  44. return strprintf(
  45. "CAlert(\n"
  46. " nVersion = %d\n"
  47. " nRelayUntil = %d\n"
  48. " nExpiration = %d\n"
  49. " nID = %d\n"
  50. " nCancel = %d\n"
  51. " setCancel = %s\n"
  52. " nMinVer = %d\n"
  53. " nMaxVer = %d\n"
  54. " setSubVer = %s\n"
  55. " nPriority = %d\n"
  56. " strComment = \"%s\"\n"
  57. " strStatusBar = \"%s\"\n"
  58. ")\n",
  59. nVersion,
  60. nRelayUntil,
  61. nExpiration,
  62. nID,
  63. nCancel,
  64. strSetCancel,
  65. nMinVer,
  66. nMaxVer,
  67. strSetSubVer,
  68. nPriority,
  69. strComment,
  70. strStatusBar);
  71. }
  72. void CUnsignedAlert::print() const
  73. {
  74. LogPrintf("%s", ToString());
  75. }
  76. void CAlert::SetNull()
  77. {
  78. CUnsignedAlert::SetNull();
  79. vchMsg.clear();
  80. vchSig.clear();
  81. }
  82. bool CAlert::IsNull() const
  83. {
  84. return (nExpiration == 0);
  85. }
  86. uint256 CAlert::GetHash() const
  87. {
  88. return Hash(this->vchMsg.begin(), this->vchMsg.end());
  89. }
  90. bool CAlert::IsInEffect() const
  91. {
  92. return (GetAdjustedTime() < nExpiration);
  93. }
  94. bool CAlert::Cancels(const CAlert& alert) const
  95. {
  96. if (!IsInEffect())
  97. return false; // this was a no-op before 31403
  98. return (alert.nID <= nCancel || setCancel.count(alert.nID));
  99. }
  100. bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const
  101. {
  102. // TODO: rework for client-version-embedded-in-strSubVer ?
  103. return (IsInEffect() &&
  104. nMinVer <= nVersion && nVersion <= nMaxVer &&
  105. (setSubVer.empty() || setSubVer.count(strSubVerIn)));
  106. }
  107. bool CAlert::AppliesToMe() const
  108. {
  109. return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
  110. }
  111. bool CAlert::RelayTo(CNode* pnode) const
  112. {
  113. if (!IsInEffect())
  114. return false;
  115. // returns true if wasn't already contained in the set
  116. if (pnode->setKnown.insert(GetHash()).second)
  117. {
  118. if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
  119. AppliesToMe() ||
  120. GetAdjustedTime() < nRelayUntil)
  121. {
  122. pnode->PushMessage("alert", *this);
  123. return true;
  124. }
  125. }
  126. return false;
  127. }
  128. bool CAlert::CheckSignature() const
  129. {
  130. CPubKey key(Params().AlertKey());
  131. if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
  132. return error("CAlert::CheckSignature() : verify signature failed");
  133. // Now unserialize the data
  134. CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
  135. sMsg >> *(CUnsignedAlert*)this;
  136. return true;
  137. }
  138. CAlert CAlert::getAlertByHash(const uint256 &hash)
  139. {
  140. CAlert retval;
  141. {
  142. LOCK(cs_mapAlerts);
  143. map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
  144. if(mi != mapAlerts.end())
  145. retval = mi->second;
  146. }
  147. return retval;
  148. }
  149. bool CAlert::ProcessAlert(bool fThread)
  150. {
  151. if (!CheckSignature())
  152. return false;
  153. if (!IsInEffect())
  154. return false;
  155. // alert.nID=max is reserved for if the alert key is
  156. // compromised. It must have a pre-defined message,
  157. // must never expire, must apply to all versions,
  158. // and must cancel all previous
  159. // alerts or it will be ignored (so an attacker can't
  160. // send an "everything is OK, don't panic" version that
  161. // cannot be overridden):
  162. int maxInt = std::numeric_limits<int>::max();
  163. if (nID == maxInt)
  164. {
  165. if (!(
  166. nExpiration == maxInt &&
  167. nCancel == (maxInt-1) &&
  168. nMinVer == 0 &&
  169. nMaxVer == maxInt &&
  170. setSubVer.empty() &&
  171. nPriority == maxInt &&
  172. strStatusBar == "URGENT: Alert key compromised, upgrade required"
  173. ))
  174. return false;
  175. }
  176. {
  177. LOCK(cs_mapAlerts);
  178. // Cancel previous alerts
  179. for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
  180. {
  181. const CAlert& alert = (*mi).second;
  182. if (Cancels(alert))
  183. {
  184. LogPrint("alert", "cancelling alert %d\n", alert.nID);
  185. uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
  186. mapAlerts.erase(mi++);
  187. }
  188. else if (!alert.IsInEffect())
  189. {
  190. LogPrint("alert", "expiring alert %d\n", alert.nID);
  191. uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
  192. mapAlerts.erase(mi++);
  193. }
  194. else
  195. mi++;
  196. }
  197. // Check if this alert has been cancelled
  198. BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
  199. {
  200. const CAlert& alert = item.second;
  201. if (alert.Cancels(*this))
  202. {
  203. LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
  204. return false;
  205. }
  206. }
  207. // Add to mapAlerts
  208. mapAlerts.insert(make_pair(GetHash(), *this));
  209. // Notify UI and -alertnotify if it applies to me
  210. if(AppliesToMe())
  211. {
  212. uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
  213. std::string strCmd = GetArg("-alertnotify", "");
  214. if (!strCmd.empty())
  215. {
  216. // Alert text should be plain ascii coming from a trusted source, but to
  217. // be safe we first strip anything not in safeChars, then add single quotes around
  218. // the whole string before passing it to the shell:
  219. std::string singleQuote("'");
  220. std::string safeStatus = SanitizeString(strStatusBar);
  221. safeStatus = singleQuote+safeStatus+singleQuote;
  222. boost::replace_all(strCmd, "%s", safeStatus);
  223. if (fThread)
  224. boost::thread t(runCommand, strCmd); // thread runs free
  225. else
  226. runCommand(strCmd);
  227. }
  228. }
  229. }
  230. LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
  231. return true;
  232. }