-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
553 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,256 @@ | ||
// Copyright (c) 2010 Satoshi Nakamoto | ||
// Copyright (c) 2009-2015 The Bitcoin Core developers | ||
// Distributed under the MIT software license, see the accompanying | ||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
#include <alert.h> | ||
|
||
#include <clientversion.h> | ||
#include <net.h> | ||
#include <pubkey.h> | ||
#include <timedata.h> | ||
#include <ui_interface.h> | ||
#include <util.h> | ||
#include <utilstrencodings.h> | ||
#include <netmessagemaker.h> | ||
|
||
#include <stdint.h> | ||
#include <algorithm> | ||
#include <map> | ||
|
||
#include <boost/algorithm/string/classification.hpp> | ||
#include <boost/algorithm/string/replace.hpp> | ||
#include <boost/thread.hpp> | ||
|
||
using namespace std; | ||
|
||
map<uint256, CAlert> mapAlerts; | ||
CCriticalSection cs_mapAlerts; | ||
|
||
void CUnsignedAlert::SetNull() | ||
{ | ||
nVersion = 1; | ||
nRelayUntil = 0; | ||
nExpiration = 0; | ||
nID = 0; | ||
nCancel = 0; | ||
setCancel.clear(); | ||
nMinVer = 0; | ||
nMaxVer = 0; | ||
setSubVer.clear(); | ||
nPriority = 0; | ||
|
||
strComment.clear(); | ||
strStatusBar.clear(); | ||
strReserved.clear(); | ||
} | ||
|
||
std::string CUnsignedAlert::ToString() const | ||
{ | ||
std::string strSetCancel; | ||
for(int n : setCancel) | ||
strSetCancel += strprintf("%d ", n); | ||
std::string strSetSubVer; | ||
for(const std::string& str : setSubVer) | ||
strSetSubVer += "\"" + str + "\" "; | ||
return strprintf( | ||
"CAlert(\n" | ||
" nVersion = %d\n" | ||
" nRelayUntil = %d\n" | ||
" nExpiration = %d\n" | ||
" nID = %d\n" | ||
" nCancel = %d\n" | ||
" setCancel = %s\n" | ||
" nMinVer = %d\n" | ||
" nMaxVer = %d\n" | ||
" setSubVer = %s\n" | ||
" nPriority = %d\n" | ||
" strComment = \"%s\"\n" | ||
" strStatusBar = \"%s\"\n" | ||
")\n", | ||
nVersion, | ||
nRelayUntil, | ||
nExpiration, | ||
nID, | ||
nCancel, | ||
strSetCancel, | ||
nMinVer, | ||
nMaxVer, | ||
strSetSubVer, | ||
nPriority, | ||
strComment, | ||
strStatusBar); | ||
} | ||
|
||
void CAlert::SetNull() | ||
{ | ||
CUnsignedAlert::SetNull(); | ||
vchMsg.clear(); | ||
vchSig.clear(); | ||
} | ||
|
||
bool CAlert::IsNull() const | ||
{ | ||
return (nExpiration == 0); | ||
} | ||
|
||
uint256 CAlert::GetHash() const | ||
{ | ||
return Hash(this->vchMsg.begin(), this->vchMsg.end()); | ||
} | ||
|
||
bool CAlert::IsInEffect() const | ||
{ | ||
return (GetAdjustedTime() < nExpiration); | ||
} | ||
|
||
bool CAlert::Cancels(const CAlert& alert) const | ||
{ | ||
if (!IsInEffect()) | ||
return false; // this was a no-op before 31403 | ||
return (alert.nID <= nCancel || setCancel.count(alert.nID)); | ||
} | ||
|
||
bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const | ||
{ | ||
// TODO: rework for client-version-embedded-in-strSubVer ? | ||
return (IsInEffect() && | ||
nMinVer <= nVersion && nVersion <= nMaxVer && | ||
(setSubVer.empty() || setSubVer.count(strSubVerIn))); | ||
} | ||
|
||
bool CAlert::AppliesToMe() const | ||
{ | ||
return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>())); | ||
} | ||
|
||
bool CAlert::RelayTo(CNode* pnode) const | ||
{ | ||
const CNetMsgMaker msgMaker(pnode->GetSendVersion()); | ||
|
||
if (!IsInEffect()) | ||
return false; | ||
// don't relay to nodes which haven't sent their version message | ||
if (pnode->nVersion == 0) | ||
return false; | ||
// returns true if wasn't already contained in the set | ||
if (pnode->setKnown.insert(GetHash()).second) | ||
{ | ||
if (AppliesTo(pnode->nVersion, pnode->strSubVer) || | ||
AppliesToMe() || | ||
GetAdjustedTime() < nRelayUntil) | ||
{ | ||
CConnman& connman = *g_connman; | ||
connman.PushMessage(pnode, msgMaker.Make(NetMsgType::ALERT, *this)); | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const | ||
{ | ||
CPubKey key(alertKey); | ||
if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) | ||
return error("CAlert::CheckSignature(): verify signature failed"); | ||
|
||
// Now unserialize the data | ||
CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); | ||
sMsg >> *(CUnsignedAlert*)this; | ||
return true; | ||
} | ||
|
||
CAlert CAlert::getAlertByHash(const uint256 &hash) | ||
{ | ||
CAlert retval; | ||
{ | ||
LOCK(cs_mapAlerts); | ||
map<uint256, CAlert>::iterator mi = mapAlerts.find(hash); | ||
if(mi != mapAlerts.end()) | ||
retval = mi->second; | ||
} | ||
return retval; | ||
} | ||
|
||
bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey) | ||
{ | ||
if (!CheckSignature(alertKey)) | ||
return error("CAlert::ProcessAlert: verify signature failed"); | ||
if (!IsInEffect()) | ||
return error("CAlert::ProcessAlert: Expired"); | ||
|
||
// alert.nID=max is reserved for if the alert key is | ||
// compromised. It must have a pre-defined message, | ||
// must never expire, must apply to all versions, | ||
// and must cancel all previous | ||
// alerts or it will be ignored (so an attacker can't | ||
// send an "everything is OK, don't panic" version that | ||
// cannot be overridden): | ||
int maxInt = std::numeric_limits<int>::max(); | ||
if (nID == maxInt) | ||
{ | ||
if (!( | ||
nExpiration == maxInt && | ||
nCancel == (maxInt-1) && | ||
nMinVer == 0 && | ||
nMaxVer == maxInt && | ||
setSubVer.empty() && | ||
nPriority == maxInt && | ||
strStatusBar == "URGENT: Alert key compromised, upgrade required" | ||
)) | ||
return false; | ||
} | ||
|
||
{ | ||
LOCK(cs_mapAlerts); | ||
// Cancel previous alerts | ||
for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) | ||
{ | ||
const CAlert& alert = (*mi).second; | ||
if (Cancels(alert)) | ||
{ | ||
uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); | ||
mapAlerts.erase(mi++); | ||
} | ||
else if (!alert.IsInEffect()) | ||
{ | ||
uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); | ||
mapAlerts.erase(mi++); | ||
} | ||
else | ||
mi++; | ||
} | ||
|
||
// Check if this alert has been cancelled | ||
for (auto& item : mapAlerts) | ||
{ | ||
const CAlert& alert = item.second; | ||
if (alert.Cancels(*this)) | ||
return error("CAlert::ProcessAlert: Cancelled"); | ||
} | ||
|
||
// Add to mapAlerts | ||
mapAlerts.insert(make_pair(GetHash(), *this)); | ||
|
||
if(AppliesToMe()) | ||
{ | ||
uiInterface.NotifyAlertChanged(GetHash(), CT_NEW); | ||
Notify(strStatusBar); | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
void CAlert::Notify(const std::string& strMessage) | ||
{ | ||
// Alert text should be plain ascii coming from a trusted source, but to | ||
// be safe we first strip anything not in safeChars, then add single quotes around | ||
// the whole string before passing it to the shell: | ||
std::string singleQuote("'"); | ||
std::string safeStatus = SanitizeString(strMessage); | ||
safeStatus = singleQuote+safeStatus+singleQuote; | ||
|
||
std::thread t(runCommand, safeStatus); | ||
t.detach(); // thread runs free | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// Copyright (c) 2010 Satoshi Nakamoto | ||
// Copyright (c) 2009-2015 The Bitcoin Core developers | ||
// Distributed under the MIT software license, see the accompanying | ||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
#ifndef BITCOIN_ALERT_H | ||
#define BITCOIN_ALERT_H | ||
|
||
#include <serialize.h> | ||
#include <sync.h> | ||
|
||
#include <map> | ||
#include <set> | ||
#include <stdint.h> | ||
#include <string> | ||
|
||
class CAlert; | ||
class CNode; | ||
class uint256; | ||
|
||
extern std::map<uint256, CAlert> mapAlerts; | ||
extern CCriticalSection cs_mapAlerts; | ||
|
||
/** Alerts are for notifying old versions if they become too obsolete and | ||
* need to upgrade. The message is displayed in the status bar. | ||
* Alert messages are broadcast as a vector of signed data. Unserializing may | ||
* not read the entire buffer if the alert is for a newer version, but older | ||
* versions can still relay the original data. | ||
*/ | ||
class CUnsignedAlert | ||
{ | ||
public: | ||
int nVersion; | ||
int64_t nRelayUntil; // when newer nodes stop relaying to newer nodes | ||
int64_t nExpiration; | ||
int nID; | ||
int nCancel; | ||
std::set<int> setCancel; | ||
int nMinVer; // lowest version inclusive | ||
int nMaxVer; // highest version inclusive | ||
std::set<std::string> setSubVer; // empty matches all | ||
int nPriority; | ||
|
||
// Actions | ||
std::string strComment; | ||
std::string strStatusBar; | ||
std::string strReserved; | ||
|
||
ADD_SERIALIZE_METHODS; | ||
|
||
template <typename Stream, typename Operation> | ||
inline void SerializationOp(Stream& s, Operation ser_action) { | ||
READWRITE(this->nVersion); | ||
nVersion = this->nVersion; | ||
READWRITE(nRelayUntil); | ||
READWRITE(nExpiration); | ||
READWRITE(nID); | ||
READWRITE(nCancel); | ||
READWRITE(setCancel); | ||
READWRITE(nMinVer); | ||
READWRITE(nMaxVer); | ||
READWRITE(setSubVer); | ||
READWRITE(nPriority); | ||
|
||
READWRITE(LIMITED_STRING(strComment, 65536)); | ||
READWRITE(LIMITED_STRING(strStatusBar, 256)); | ||
READWRITE(LIMITED_STRING(strReserved, 256)); | ||
} | ||
|
||
void SetNull(); | ||
|
||
std::string ToString() const; | ||
}; | ||
|
||
/** An alert is a combination of a serialized CUnsignedAlert and a signature. */ | ||
class CAlert : public CUnsignedAlert | ||
{ | ||
public: | ||
std::vector<unsigned char> vchMsg; | ||
std::vector<unsigned char> vchSig; | ||
|
||
CAlert() | ||
{ | ||
SetNull(); | ||
} | ||
|
||
ADD_SERIALIZE_METHODS; | ||
|
||
template <typename Stream, typename Operation> | ||
inline void SerializationOp(Stream& s, Operation ser_action) { | ||
READWRITE(vchMsg); | ||
READWRITE(vchSig); | ||
} | ||
|
||
void SetNull(); | ||
bool IsNull() const; | ||
uint256 GetHash() const; | ||
bool IsInEffect() const; | ||
bool Cancels(const CAlert& alert) const; | ||
bool AppliesTo(int nVersion, const std::string& strSubVerIn) const; | ||
bool AppliesToMe() const; | ||
bool RelayTo(CNode* pnode) const; | ||
bool CheckSignature(const std::vector<unsigned char>& alertKey) const; | ||
bool ProcessAlert(const std::vector<unsigned char>& alertKey); | ||
static void Notify(const std::string& strMessage); | ||
|
||
/* | ||
* Get copy of (active) alert object by hash. Returns a null alert if it is not found. | ||
*/ | ||
static CAlert getAlertByHash(const uint256 &hash); | ||
}; | ||
|
||
#endif // BITCOIN_ALERT_H |
Oops, something went wrong.