Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

mnauth.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-2020 The Dash Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <evo/mnauth.h>
6 
7 #include <evo/deterministicmns.h>
8 #include <llmq/quorums_utils.h>
12 #include <net.h>
13 #include <net_processing.h>
14 #include <netmessagemaker.h>
15 #include <validation.h>
16 
17 #include <unordered_set>
18 
19 void CMNAuth::PushMNAUTH(CNode* pnode, CConnman& connman)
20 {
22  return;
23  }
24 
25  uint256 signHash;
26  {
27  LOCK(pnode->cs_mnauth);
28  if (pnode->receivedMNAuthChallenge.IsNull()) {
29  return;
30  }
31  // We include fInbound in signHash to forbid interchanging of challenges by a man in the middle (MITM). This way
32  // we protect ourselves against MITM in this form:
33  // node1 <- Eve -> node2
34  // It does not protect against:
35  // node1 -> Eve -> node2
36  // This is ok as we only use MNAUTH as a DoS protection and not for sensitive stuff
37  int nOurNodeVersion{PROTOCOL_VERSION};
38  if (Params().NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) {
39  nOurNodeVersion = gArgs.GetArg("-pushversion", PROTOCOL_VERSION);
40  }
41  if (pnode->nVersion < MNAUTH_NODE_VER_VERSION || nOurNodeVersion < MNAUTH_NODE_VER_VERSION) {
42  signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, pnode->receivedMNAuthChallenge, pnode->fInbound));
43  } else {
44  signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, pnode->receivedMNAuthChallenge, pnode->fInbound, nOurNodeVersion));
45  }
46  }
47 
48  CMNAuth mnauth;
50  mnauth.sig = activeMasternodeInfo.blsKeyOperator->Sign(signHash);
51 
52  LogPrint(BCLog::NET_NETCONN, "CMNAuth::%s -- Sending MNAUTH, peer=%d\n", __func__, pnode->GetId());
53 
54  connman.PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::MNAUTH, mnauth));
55 }
56 
57 void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
58 {
60  // we can't verify MNAUTH messages when we don't have the latest MN list
61  return;
62  }
63 
64  if (strCommand == NetMsgType::MNAUTH) {
65  CMNAuth mnauth;
66  vRecv >> mnauth;
67 
68  // only one MNAUTH allowed
69  bool fAlreadyHaveMNAUTH = false;
70  {
71  LOCK(pnode->cs_mnauth);
72  fAlreadyHaveMNAUTH = !pnode->verifiedProRegTxHash.IsNull();
73  }
74  if (fAlreadyHaveMNAUTH) {
75  LOCK(cs_main);
76  Misbehaving(pnode->GetId(), 100, "duplicate mnauth");
77  return;
78  }
79 
80  if ((~pnode->nServices) & (NODE_NETWORK | NODE_BLOOM)) {
81  // either NODE_NETWORK or NODE_BLOOM bit is missing in node's services
82  LOCK(cs_main);
83  Misbehaving(pnode->GetId(), 100, "mnauth from a node with invalid services");
84  return;
85  }
86 
87  if (mnauth.proRegTxHash.IsNull()) {
88  LOCK(cs_main);
89  Misbehaving(pnode->GetId(), 100, "empty mnauth proRegTxHash");
90  return;
91  }
92 
93  if (!mnauth.sig.IsValid()) {
94  LOCK(cs_main);
95  Misbehaving(pnode->GetId(), 100, "invalid mnauth signature");
96  return;
97  }
98 
99  auto mnList = deterministicMNManager->GetListAtChainTip();
100  auto dmn = mnList.GetMN(mnauth.proRegTxHash);
101  if (!dmn) {
102  LOCK(cs_main);
103  // in case node was unlucky and not up to date, just let it be connected as a regular node, which gives it
104  // a chance to get up-to-date and thus realize that it's not a MN anymore. We still give it a
105  // low DoS score.
106  Misbehaving(pnode->GetId(), 10, "missing mnauth masternode");
107  return;
108  }
109 
110  uint256 signHash;
111  {
112  LOCK(pnode->cs_mnauth);
113  int nOurNodeVersion{PROTOCOL_VERSION};
114  if (Params().NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) {
115  nOurNodeVersion = gArgs.GetArg("-pushversion", PROTOCOL_VERSION);
116  }
117  // See comment in PushMNAUTH (fInbound is negated here as we're on the other side of the connection)
118  if (pnode->nVersion < MNAUTH_NODE_VER_VERSION || nOurNodeVersion < MNAUTH_NODE_VER_VERSION) {
119  signHash = ::SerializeHash(std::make_tuple(dmn->pdmnState->pubKeyOperator, pnode->sentMNAuthChallenge, !pnode->fInbound));
120  } else {
121  signHash = ::SerializeHash(std::make_tuple(dmn->pdmnState->pubKeyOperator, pnode->sentMNAuthChallenge, !pnode->fInbound, pnode->nVersion.load()));
122  }
123  LogPrint(BCLog::NET_NETCONN, "CMNAuth::%s -- constructed signHash for nVersion %d, peer=%d\n", __func__, pnode->nVersion, pnode->GetId());
124  }
125 
126  if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), signHash)) {
127  LOCK(cs_main);
128  // Same as above, MN seems to not know its fate yet, so give it a chance to update. If this is a
129  // malicious node (DoSing us), it'll get banned soon.
130  Misbehaving(pnode->GetId(), 10, "mnauth signature verification failed");
131  return;
132  }
133 
134  if (!pnode->fInbound) {
135  mmetaman.GetMetaInfo(mnauth.proRegTxHash)->SetLastOutboundSuccess(GetAdjustedTime());
136  if (pnode->fMasternodeProbe) {
137  LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- Masternode probe successful for %s, disconnecting. peer=%d\n",
138  mnauth.proRegTxHash.ToString(), pnode->GetId());
139  pnode->fDisconnect = true;
140  return;
141  }
142  }
143 
144  connman.ForEachNode([&](CNode* pnode2) {
145  if (pnode->fDisconnect) {
146  // we've already disconnected the new peer
147  return;
148  }
149 
150  if (pnode2->verifiedProRegTxHash == mnauth.proRegTxHash) {
151  if (fMasternodeMode) {
152  auto deterministicOutbound = llmq::CLLMQUtils::DeterministicOutboundConnection(activeMasternodeInfo.proTxHash, mnauth.proRegTxHash);
153  LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- Masternode %s has already verified as peer %d, deterministicOutbound=%s. peer=%d\n",
154  mnauth.proRegTxHash.ToString(), pnode2->GetId(), deterministicOutbound.ToString(), pnode->GetId());
155  if (deterministicOutbound == activeMasternodeInfo.proTxHash) {
156  if (pnode2->fInbound) {
157  LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- dropping old inbound, peer=%d\n", pnode2->GetId());
158  pnode2->fDisconnect = true;
159  } else if (pnode->fInbound) {
160  LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- dropping new inbound, peer=%d\n", pnode->GetId());
161  pnode->fDisconnect = true;
162  }
163  } else {
164  if (!pnode2->fInbound) {
165  LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- dropping old outbound, peer=%d\n", pnode2->GetId());
166  pnode2->fDisconnect = true;
167  } else if (!pnode->fInbound) {
168  LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- dropping new outbound, peer=%d\n", pnode->GetId());
169  pnode->fDisconnect = true;
170  }
171  }
172  } else {
173  LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- Masternode %s has already verified as peer %d, dropping new connection. peer=%d\n",
174  mnauth.proRegTxHash.ToString(), pnode2->GetId(), pnode->GetId());
175  pnode->fDisconnect = true;
176  }
177  }
178  });
179 
180  if (pnode->fDisconnect) {
181  return;
182  }
183 
184  {
185  LOCK(pnode->cs_mnauth);
186  pnode->verifiedProRegTxHash = mnauth.proRegTxHash;
187  pnode->verifiedPubKeyHash = dmn->pdmnState->pubKeyOperator.GetHash();
188  }
189 
190  LogPrint(BCLog::NET_NETCONN, "CMNAuth::%s -- Valid MNAUTH for %s, peer=%d\n", __func__, mnauth.proRegTxHash.ToString(), pnode->GetId());
191  }
192 }
193 
195 {
196  // we're only interested in updated/removed MNs. Added MNs are of no interest for us
197  if (diff.updatedMNs.empty() && diff.removedMns.empty()) {
198  return;
199  }
200 
201  g_connman->ForEachNode([&](CNode* pnode) {
202  LOCK(pnode->cs_mnauth);
203  if (pnode->verifiedProRegTxHash.IsNull()) {
204  return;
205  }
206  auto verifiedDmn = oldMNList.GetMN(pnode->verifiedProRegTxHash);
207  if (!verifiedDmn) {
208  return;
209  }
210  bool doRemove = false;
211  if (diff.removedMns.count(verifiedDmn->GetInternalId())) {
212  doRemove = true;
213  } else {
214  auto it = diff.updatedMNs.find(verifiedDmn->GetInternalId());
215  if (it != diff.updatedMNs.end()) {
216  if ((it->second.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && it->second.state.pubKeyOperator.GetHash() != pnode->verifiedPubKeyHash) {
217  doRemove = true;
218  }
219  }
220  }
221 
222  if (doRemove) {
223  LogPrint(BCLog::NET_NETCONN, "CMNAuth::NotifyMasternodeListChanged -- Disconnecting MN %s due to key changed/removed, peer=%d\n",
224  pnode->verifiedProRegTxHash.ToString(), pnode->GetId());
225  pnode->fDisconnect = true;
226  }
227  });
228 }
std::string NetworkIDString() const
Return the BIP70 network string (main, test or regtest)
Definition: chainparams.h:76
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: util.cpp:784
CMasternodeSync masternodeSync
int GetSendVersion() const
Definition: net.cpp:887
CDeterministicMNCPtr GetMN(const uint256 &proTxHash) const
CCriticalSection cs_main
Definition: validation.cpp:213
CCriticalSection cs_mnauth
Definition: net.h:938
void PushMessage(CNode *pnode, CSerializedNetMsg &&msg)
Definition: net.cpp:3733
uint256 verifiedPubKeyHash
Definition: net.h:942
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:103
bool IsBlockchainSynced()
static void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList &oldMNList, const CDeterministicMNListDiff &diff)
Definition: mnauth.cpp:194
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
bool IsNull() const
Definition: uint256.h:33
std::atomic< ServiceFlags > nServices
Definition: net.h:805
void ForEachNode(const Condition &cond, Callable &&func)
Definition: net.h:288
CBLSSignature sig
Definition: mnauth.h:40
static const std::string MAIN
BIP70 chain name strings (main, test or regtest)
CMasternodeMetaMan mmetaman
uint256 SerializeHash(const T &obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Compute the 256-bit hash of an object&#39;s serialization.
Definition: hash.h:254
void Misbehaving(NodeId pnode, int howmuch, const std::string &message)
Increase a node&#39;s misbehavior score.
bool fMasternodeMode
Definition: util.cpp:93
CActiveMasternodeInfo activeMasternodeInfo
#define LOCK(cs)
Definition: sync.h:178
uint256 proRegTxHash
Definition: mnauth.h:39
Definition: net.h:136
bool fMasternodeProbe
Definition: net.h:866
uint256 sentMNAuthChallenge
Definition: net.h:939
std::string ToString() const
Definition: uint256.cpp:62
NodeId GetId() const
Definition: net.h:973
std::atomic_bool fDisconnect
Definition: net.h:853
#define LogPrint(category,...)
Definition: util.h:214
static void ProcessMessage(CNode *pnode, const std::string &strCommand, CDataStream &vRecv, CConnman &connman)
Definition: mnauth.cpp:57
static void PushMNAUTH(CNode *pnode, CConnman &connman)
Definition: mnauth.cpp:19
256-bit opaque blob.
Definition: uint256.h:123
ArgsManager gArgs
Definition: util.cpp:108
uint256 receivedMNAuthChallenge
Definition: net.h:940
This class handles the p2p message MNAUTH.
Definition: mnauth.h:36
uint256 verifiedProRegTxHash
Definition: net.h:941
static const int MNAUTH_NODE_VER_VERSION
protocol version is included in MNAUTH starting with this version
Definition: version.h:58
const bool fInbound
Definition: net.h:851
const CChainParams & Params()
Return the currently selected parameters.
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:14
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: util.cpp:808
int64_t GetAdjustedTime()
Definition: timedata.cpp:35
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:97
std::atomic< int > nVersion
Definition: net.h:838
const char * MNAUTH
Definition: protocol.cpp:77
std::unique_ptr< CBLSPublicKey > blsPubKeyOperator
Information about a peer.
Definition: net.h:800
std::set< uint64_t > removedMns
std::unique_ptr< CBLSSecretKey > blsKeyOperator
std::map< uint64_t, CDeterministicMNStateDiff > updatedMNs
CMasternodeMetaInfoPtr GetMetaInfo(const uint256 &proTxHash, bool fCreate=true)
Released under the MIT license