LCOV - code coverage report
Current view: top level - src - alert.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 72 112 64.3 %
Date: 2015-10-12 22:39:14 Functions: 10 16 62.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11