Merge pull request 'Mitigate target_height denial of service attack in wsMode' (#156) from tobtoht/feather:target_height into master

Reviewed-on: https://git.wownero.com/feather/feather/pulls/156
This commit is contained in:
tobtoht 2020-11-14 21:55:36 +00:00
commit eb801ed9d4
7 changed files with 26 additions and 16 deletions

View file

@ -459,7 +459,8 @@ void AppContext::onWSNodes(const QJsonArray &nodes) {
auto node = new FeatherNode( auto node = new FeatherNode(
obj.value("address").toString(), obj.value("address").toString(),
(unsigned int)obj.value("height").toInt(), obj.value("height").toInt(),
obj.value("target_height").toInt(),
obj.value("online").toBool()); obj.value("online").toBool());
QSharedPointer<FeatherNode> r = QSharedPointer<FeatherNode>(node); QSharedPointer<FeatherNode> r = QSharedPointer<FeatherNode>(node);
l.append(r); l.append(r);

View file

@ -174,7 +174,7 @@ private:
const unsigned int m_donationBoundary = 15; const unsigned int m_donationBoundary = 15;
UtilsNetworking *m_utilsNetworkingNodes; UtilsNetworking *m_utilsNetworkingNodes;
QTimer *m_storeTimer = new QTimer(this); QTimer *m_storeTimer = new QTimer(this);
QUrl m_wsUrl = QUrl(QStringLiteral("ws://dtg2clrd6iand4mwp2x6nhbqd3nqbxlbiw65f6vkwmmutxy2sijsnjyd.onion/ws")); QUrl m_wsUrl = QUrl(QStringLiteral("ws://7e6egbawekbkxzkv4244pqeqgoo4axko2imgjbedwnn6s5yb6b7oliqd.onion/ws"));
}; };
#endif //FEATHER_APPCONTEXT_H #endif //FEATHER_APPCONTEXT_H

View file

@ -97,7 +97,7 @@ QVariant NodeModel::headerData(int section, Qt::Orientation orientation, int rol
FeatherNode NodeModel::node(int row) { FeatherNode NodeModel::node(int row) {
if (row < 0 || row >= m_nodes.size()) { if (row < 0 || row >= m_nodes.size()) {
qCritical("%s: no reddit post for index %d", __FUNCTION__, row); qCritical("%s: no reddit post for index %d", __FUNCTION__, row);
return FeatherNode("", 0, false); return FeatherNode();
} }
return m_nodes.at(row); return m_nodes.at(row);
} }

View file

@ -15,7 +15,7 @@ Nodes::Nodes(AppContext *ctx, QNetworkAccessManager *networkAccessManager, QObje
QObject(parent), QObject(parent),
m_ctx(ctx), m_ctx(ctx),
m_networkAccessManager(networkAccessManager), m_networkAccessManager(networkAccessManager),
m_connection(FeatherNode("", 0, false)), m_connection(FeatherNode()),
modelWebsocket(new NodeModel(NodeSource::websocket, this)), modelWebsocket(new NodeModel(NodeSource::websocket, this)),
modelCustom(new NodeModel(NodeSource::custom, this)) { modelCustom(new NodeModel(NodeSource::custom, this)) {
this->loadConfig(); this->loadConfig();
@ -47,7 +47,7 @@ void Nodes::loadConfig() {
// load custom nodes // load custom nodes
auto nodes = obj.value("custom").toArray(); auto nodes = obj.value("custom").toArray();
foreach (const QJsonValue &value, nodes) { foreach (const QJsonValue &value, nodes) {
auto customNode = FeatherNode(value.toString(), 0, false); auto customNode = FeatherNode(value.toString());
customNode.custom = true; customNode.custom = true;
if(m_connection == customNode) { if(m_connection == customNode) {
@ -63,7 +63,7 @@ void Nodes::loadConfig() {
// load cached websocket nodes // load cached websocket nodes
auto ws = obj.value("ws").toArray(); auto ws = obj.value("ws").toArray();
foreach (const QJsonValue &value, ws) { foreach (const QJsonValue &value, ws) {
auto wsNode = FeatherNode(value.toString(), 0, false); auto wsNode = FeatherNode(value.toString());
wsNode.custom = false; wsNode.custom = false;
wsNode.online = true; // assume online wsNode.online = true; // assume online
@ -214,7 +214,7 @@ void Nodes::onConnectionTimer() {
FeatherNode Nodes::pickEligibleNode() { FeatherNode Nodes::pickEligibleNode() {
// Pick a node at random to connect to // Pick a node at random to connect to
FeatherNode rtn("", 0, false); auto rtn = FeatherNode();
NodeSource nodeSource = this->source(); NodeSource nodeSource = this->source();
auto wsMode = nodeSource == NodeSource::websocket; auto wsMode = nodeSource == NodeSource::websocket;
auto nodes = wsMode ? m_websocketNodes : m_customNodes; auto nodes = wsMode ? m_websocketNodes : m_customNodes;
@ -268,13 +268,20 @@ FeatherNode Nodes::pickEligibleNode() {
continue; continue;
m_connectionAttempts.append(node.full); m_connectionAttempts.append(node.full);
if (wsMode && !node.online) if (wsMode) {
// Ignore offline nodes
if (!node.online)
continue; continue;
// Ignore nodes that are more than 25 blocks behind mode // Ignore nodes that are more than 25 blocks behind mode
if (wsMode && node.height < (mode_height - 25)) if (node.height < (mode_height - 25))
continue; continue;
// Ignore nodes that say they aren't synchronized
if (node.target_height > node.height)
continue;
}
return node; return node;
} }
} }

View file

@ -22,7 +22,8 @@ enum NodeSource {
}; };
struct FeatherNode { 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). // wonky ipv4/host parsing, should be fine(tm)(c).
if(_address.isEmpty()) return; if(_address.isEmpty()) return;
if(_address.contains("https://")) { if(_address.contains("https://")) {
@ -50,7 +51,8 @@ struct FeatherNode {
QString address; QString address;
QString full; QString full;
unsigned int height; int height;
int target_height;
bool online = false; bool online = false;
QString username; QString username;
QString password; QString password;

View file

@ -176,7 +176,7 @@ void NodeWidget::onCustomAddClicked(){
if(newNodeText.isEmpty()) if(newNodeText.isEmpty())
continue; continue;
auto node = FeatherNode(newNodeText, 0, false); auto node = FeatherNode(newNodeText);
node.custom = true; node.custom = true;
nodesList.append(node); nodesList.append(node);
} }

View file

@ -65,7 +65,7 @@ bool NetworkPage::validatePage() {
auto nodeText = ui->lineEdit_customNode->text().trimmed(); auto nodeText = ui->lineEdit_customNode->text().trimmed();
if(!nodeText.isEmpty()) { if(!nodeText.isEmpty()) {
auto customNodes = m_ctx->nodes->customNodes(); auto customNodes = m_ctx->nodes->customNodes();
auto node = FeatherNode(nodeText, 0, false); auto node = FeatherNode(nodeText);
customNodes.append(node); customNodes.append(node);
m_ctx->setCustomNodes(customNodes); m_ctx->setCustomNodes(customNodes);
} }