From d9dfef021f7791221a8ddb2b0151acd9d849a598 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sat, 14 Nov 2020 22:42:41 +0100 Subject: [PATCH] Mitigate target_height attack --- src/appcontext.cpp | 3 ++- src/model/NodeModel.cpp | 2 +- src/utils/nodes.cpp | 25 ++++++++++++++++--------- src/utils/nodes.h | 6 ++++-- src/widgets/nodewidget.cpp | 2 +- src/wizard/network.cpp | 2 +- 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/appcontext.cpp b/src/appcontext.cpp index aac53df..5017164 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -459,7 +459,8 @@ void AppContext::onWSNodes(const QJsonArray &nodes) { auto node = new FeatherNode( obj.value("address").toString(), - (unsigned int)obj.value("height").toInt(), + obj.value("height").toInt(), + obj.value("target_height").toInt(), obj.value("online").toBool()); QSharedPointer r = QSharedPointer(node); l.append(r); diff --git a/src/model/NodeModel.cpp b/src/model/NodeModel.cpp index 43c2735..6b465b5 100644 --- a/src/model/NodeModel.cpp +++ b/src/model/NodeModel.cpp @@ -97,7 +97,7 @@ QVariant NodeModel::headerData(int section, Qt::Orientation orientation, int rol FeatherNode NodeModel::node(int row) { if (row < 0 || row >= m_nodes.size()) { qCritical("%s: no reddit post for index %d", __FUNCTION__, row); - return FeatherNode("", 0, false); + return FeatherNode(); } return m_nodes.at(row); } diff --git a/src/utils/nodes.cpp b/src/utils/nodes.cpp index 0300d30..0dd07d9 100644 --- a/src/utils/nodes.cpp +++ b/src/utils/nodes.cpp @@ -15,7 +15,7 @@ Nodes::Nodes(AppContext *ctx, QNetworkAccessManager *networkAccessManager, QObje QObject(parent), m_ctx(ctx), m_networkAccessManager(networkAccessManager), - m_connection(FeatherNode("", 0, false)), + m_connection(FeatherNode()), modelWebsocket(new NodeModel(NodeSource::websocket, this)), modelCustom(new NodeModel(NodeSource::custom, this)) { this->loadConfig(); @@ -47,7 +47,7 @@ void Nodes::loadConfig() { // load custom nodes auto nodes = obj.value("custom").toArray(); foreach (const QJsonValue &value, nodes) { - auto customNode = FeatherNode(value.toString(), 0, false); + auto customNode = FeatherNode(value.toString()); customNode.custom = true; if(m_connection == customNode) { @@ -63,7 +63,7 @@ void Nodes::loadConfig() { // load cached websocket nodes auto ws = obj.value("ws").toArray(); foreach (const QJsonValue &value, ws) { - auto wsNode = FeatherNode(value.toString(), 0, false); + auto wsNode = FeatherNode(value.toString()); wsNode.custom = false; wsNode.online = true; // assume online @@ -214,7 +214,7 @@ void Nodes::onConnectionTimer() { FeatherNode Nodes::pickEligibleNode() { // Pick a node at random to connect to - FeatherNode rtn("", 0, false); + auto rtn = FeatherNode(); NodeSource nodeSource = this->source(); auto wsMode = nodeSource == NodeSource::websocket; auto nodes = wsMode ? m_websocketNodes : m_customNodes; @@ -268,12 +268,19 @@ FeatherNode Nodes::pickEligibleNode() { continue; m_connectionAttempts.append(node.full); - if (wsMode && !node.online) - continue; + if (wsMode) { + // Ignore offline nodes + if (!node.online) + continue; - // Ignore nodes that are more than 25 blocks behind mode - if (wsMode && node.height < (mode_height - 25)) - continue; + // Ignore nodes that are more than 25 blocks behind mode + if (node.height < (mode_height - 25)) + continue; + + // Ignore nodes that say they aren't synchronized + if (node.target_height > node.height) + continue; + } return node; } diff --git a/src/utils/nodes.h b/src/utils/nodes.h index b5699e8..37ba854 100644 --- a/src/utils/nodes.h +++ b/src/utils/nodes.h @@ -22,7 +22,8 @@ enum NodeSource { }; struct FeatherNode { - FeatherNode(QString _address, unsigned int height, bool online) : height(height), online(online){ + explicit FeatherNode(QString _address = "", int height = 0, int target_height = 0, bool online = false) + : height(height), target_height(target_height), online(online){ // wonky ipv4/host parsing, should be fine(tm)(c). if(_address.isEmpty()) return; if(_address.contains("https://")) { @@ -50,7 +51,8 @@ struct FeatherNode { QString address; QString full; - unsigned int height; + int height; + int target_height; bool online = false; QString username; QString password; diff --git a/src/widgets/nodewidget.cpp b/src/widgets/nodewidget.cpp index c1adaab..ba5f2e5 100644 --- a/src/widgets/nodewidget.cpp +++ b/src/widgets/nodewidget.cpp @@ -176,7 +176,7 @@ void NodeWidget::onCustomAddClicked(){ if(newNodeText.isEmpty()) continue; - auto node = FeatherNode(newNodeText, 0, false); + auto node = FeatherNode(newNodeText); node.custom = true; nodesList.append(node); } diff --git a/src/wizard/network.cpp b/src/wizard/network.cpp index 3ceaec0..f3cbd23 100644 --- a/src/wizard/network.cpp +++ b/src/wizard/network.cpp @@ -65,7 +65,7 @@ bool NetworkPage::validatePage() { auto nodeText = ui->lineEdit_customNode->text().trimmed(); if(!nodeText.isEmpty()) { auto customNodes = m_ctx->nodes->customNodes(); - auto node = FeatherNode(nodeText, 0, false); + auto node = FeatherNode(nodeText); customNodes.append(node); m_ctx->setCustomNodes(customNodes); }