Dash Core  0.12.2.1
P2P Digital Currency
alert.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2015 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "alert.h"
7 
8 #include "base58.h"
9 #include "clientversion.h"
10 #include "net.h"
11 #include "pubkey.h"
12 #include "timedata.h"
13 #include "ui_interface.h"
14 #include "util.h"
15 #include "utilstrencodings.h"
16 
17 #include <stdint.h>
18 #include <algorithm>
19 #include <map>
20 
21 #include <boost/algorithm/string/classification.hpp>
22 #include <boost/algorithm/string/replace.hpp>
23 #include <boost/foreach.hpp>
24 #include <boost/thread.hpp>
25 
26 using namespace std;
27 
28 map<uint256, CAlert> mapAlerts;
30 
32 {
33  nVersion = 1;
34  nRelayUntil = 0;
35  nExpiration = 0;
36  nID = 0;
37  nCancel = 0;
38  setCancel.clear();
39  nMinVer = 0;
40  nMaxVer = 0;
41  setSubVer.clear();
42  nPriority = 0;
43 
44  strComment.clear();
45  strStatusBar.clear();
46  strReserved.clear();
47 }
48 
49 std::string CUnsignedAlert::ToString() const
50 {
51  std::string strSetCancel;
52  BOOST_FOREACH(int n, setCancel)
53  strSetCancel += strprintf("%d ", n);
54  std::string strSetSubVer;
55  BOOST_FOREACH(const std::string& str, setSubVer)
56  strSetSubVer += "\"" + str + "\" ";
57  return strprintf(
58  "CAlert(\n"
59  " nVersion = %d\n"
60  " nRelayUntil = %d\n"
61  " nExpiration = %d\n"
62  " nID = %d\n"
63  " nCancel = %d\n"
64  " setCancel = %s\n"
65  " nMinVer = %d\n"
66  " nMaxVer = %d\n"
67  " setSubVer = %s\n"
68  " nPriority = %d\n"
69  " strComment = \"%s\"\n"
70  " strStatusBar = \"%s\"\n"
71  ")\n",
72  nVersion,
73  nRelayUntil,
74  nExpiration,
75  nID,
76  nCancel,
77  strSetCancel,
78  nMinVer,
79  nMaxVer,
80  strSetSubVer,
81  nPriority,
82  strComment,
83  strStatusBar);
84 }
85 
87 {
89  vchMsg.clear();
90  vchSig.clear();
91 }
92 
93 bool CAlert::IsNull() const
94 {
95  return (nExpiration == 0);
96 }
97 
99 {
100  return Hash(this->vchMsg.begin(), this->vchMsg.end());
101 }
102 
103 bool CAlert::IsInEffect() const
104 {
105  return (GetAdjustedTime() < nExpiration);
106 }
107 
108 bool CAlert::Cancels(const CAlert& alert) const
109 {
110  if (!IsInEffect())
111  return false; // this was a no-op before 31403
112  return (alert.nID <= nCancel || setCancel.count(alert.nID));
113 }
114 
115 bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const
116 {
117  // TODO: rework for client-version-embedded-in-strSubVer ?
118  return (IsInEffect() &&
119  nMinVer <= nVersion && nVersion <= nMaxVer &&
120  (setSubVer.empty() || setSubVer.count(strSubVerIn)));
121 }
122 
124 {
125  return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
126 }
127 
128 bool CAlert::RelayTo(CNode* pnode, CConnman& connman) const
129 {
130  if (!IsInEffect())
131  return false;
132  // don't relay to nodes which haven't sent their version message
133  if (pnode->nVersion == 0)
134  return false;
135  // returns true if wasn't already contained in the set
136  if (pnode->setKnown.insert(GetHash()).second)
137  {
138  if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
139  AppliesToMe() ||
140  GetAdjustedTime() < nRelayUntil)
141  {
142  connman.PushMessage(pnode, NetMsgType::ALERT, *this);
143  return true;
144  }
145  }
146  return false;
147 }
148 
150 {
152  sMsg << *(CUnsignedAlert*)this;
153  vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
154  CBitcoinSecret vchSecret;
155  if (!vchSecret.SetString(GetArg("-alertkey", "")))
156  {
157  printf("CAlert::SignAlert() : vchSecret.SetString failed\n");
158  return false;
159  }
160  CKey key = vchSecret.GetKey();
161  if (!key.Sign(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
162  {
163  printf("CAlert::SignAlert() : key.Sign failed\n");
164  return false;
165  }
166 
167  return true;
168 }
169 
170 bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const
171 {
172  CPubKey key(alertKey);
173  if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
174  return error("CAlert::CheckSignature(): verify signature failed");
175 
176  // Now unserialize the data
178  sMsg >> *(CUnsignedAlert*)this;
179  return true;
180 }
181 
183 {
184  CAlert retval;
185  {
187  map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
188  if(mi != mapAlerts.end())
189  retval = mi->second;
190  }
191  return retval;
192 }
193 
194 bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread)
195 {
196  if (!CheckSignature(alertKey))
197  return false;
198  if (!IsInEffect())
199  return false;
200 
201  // alert.nID=max is reserved for if the alert key is
202  // compromised. It must have a pre-defined message,
203  // must never expire, must apply to all versions,
204  // and must cancel all previous
205  // alerts or it will be ignored (so an attacker can't
206  // send an "everything is OK, don't panic" version that
207  // cannot be overridden):
208  int maxInt = std::numeric_limits<int>::max();
209  if (nID == maxInt)
210  {
211  if (!(
212  nExpiration == maxInt &&
213  nCancel == (maxInt-1) &&
214  nMinVer == 0 &&
215  nMaxVer == maxInt &&
216  setSubVer.empty() &&
217  nPriority == maxInt &&
218  strStatusBar == "URGENT: Alert key compromised, upgrade required"
219  ))
220  return false;
221  }
222 
223  {
225  // Cancel previous alerts
226  for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
227  {
228  const CAlert& alert = (*mi).second;
229  if (Cancels(alert))
230  {
231  LogPrint("alert", "cancelling alert %d\n", alert.nID);
233  mapAlerts.erase(mi++);
234  }
235  else if (!alert.IsInEffect())
236  {
237  LogPrint("alert", "expiring alert %d\n", alert.nID);
239  mapAlerts.erase(mi++);
240  }
241  else
242  mi++;
243  }
244 
245  // Check if this alert has been cancelled
246  BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
247  {
248  const CAlert& alert = item.second;
249  if (alert.Cancels(*this))
250  {
251  LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
252  return false;
253  }
254  }
255 
256  // Add to mapAlerts
257  mapAlerts.insert(make_pair(GetHash(), *this));
258  // Notify UI and -alertnotify if it applies to me
259  if(AppliesToMe())
260  {
262  Notify(strStatusBar, fThread);
263  }
264  }
265 
266  LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
267  return true;
268 }
269 
270 void
271 CAlert::Notify(const std::string& strMessage, bool fThread)
272 {
273  std::string strCmd = GetArg("-alertnotify", "");
274  if (strCmd.empty()) return;
275 
276  // Alert text should be plain ascii coming from a trusted source, but to
277  // be safe we first strip anything not in safeChars, then add single quotes around
278  // the whole string before passing it to the shell:
279  std::string singleQuote("'");
280  std::string safeStatus = SanitizeString(strMessage);
281  safeStatus = singleQuote+safeStatus+singleQuote;
282  boost::replace_all(strCmd, "%s", safeStatus);
283 
284  if (fThread)
285  boost::thread t(runCommand, strCmd); // thread runs free
286  else
287  runCommand(strCmd);
288 }
bool IsInEffect() const
Definition: alert.cpp:103
uint256 GetHash() const
Definition: alert.cpp:98
std::string strSubVer
Definition: net.h:697
void SetNull()
Definition: alert.cpp:31
#define strprintf
Definition: tinyformat.h:1011
boost::signals2::signal< void(const uint256 &hash, ChangeType status)> NotifyAlertChanged
Definition: ui_interface.h:98
std::string ToString() const
Definition: alert.cpp:49
bool AppliesToMe() const
Definition: alert.cpp:123
Definition: net.h:108
const_iterator end() const
Definition: streams.h:120
bool AppliesTo(int nVersion, const std::string &strSubVerIn) const
Definition: alert.cpp:115
Definition: alert.h:77
bool Sign()
Definition: alert.cpp:149
const char * ALERT
Definition: protocol.cpp:31
Definition: net.h:661
static int LogPrint(const char *category, const char *format)
Definition: util.h:126
const_iterator begin() const
Definition: streams.h:118
#define LOCK(cs)
Definition: sync.h:168
CClientUIInterface uiInterface
Definition: init.cpp:130
static bool error(const char *format)
Definition: util.h:131
map< uint256, CAlert > mapAlerts
Definition: alert.cpp:28
CCriticalSection cs_mapAlerts
Definition: alert.cpp:29
uint256 Hash(const T1 pbegin, const T1 pend)
Definition: hash.h:123
static CAlert getAlertByHash(const uint256 &hash)
Definition: alert.cpp:182
const std::string CLIENT_NAME
std::set< uint256 > setKnown
Definition: net.h:735
void SetNull()
Definition: alert.cpp:86
static const int PROTOCOL_VERSION
Definition: version.h:13
static void Notify(const std::string &strMessage, bool fThread)
Definition: alert.cpp:271
int64_t GetAdjustedTime()
Definition: timedata.cpp:33
void runCommand(const std::string &strCommand)
Definition: util.cpp:866
std::string FormatSubVersion(const std::string &name, int nClientVersion, const std::vector< std::string > &comments)
Definition: pubkey.h:37
std::string GetArg(const std::string &strArg, const std::string &strDefault)
Definition: util.cpp:441
bool Cancels(const CAlert &alert) const
Definition: alert.cpp:108
bool IsNull() const
Definition: alert.cpp:93
bool RelayTo(CNode *pnode, CConnman &connman) const
Definition: alert.cpp:128
Definition: key.h:35
bool ProcessAlert(const std::vector< unsigned char > &alertKey, bool fThread=true)
Definition: alert.cpp:194
static const int CLIENT_VERSION
Definition: clientversion.h:54
#define PAIRTYPE(t1, t2)
void PushMessage(CNode *pnode, const std::string &sCommand, Args &&... args)
Definition: net.h:199
string SanitizeString(const string &str, int rule)
std::atomic< int > nVersion
Definition: net.h:692
bool CheckSignature(const std::vector< unsigned char > &alertKey) const
Definition: alert.cpp:170