From e7e30ada8cd33f0dd4adfdb3c021b75e28232057 Mon Sep 17 00:00:00 2001 From: Anthony Bilinski Date: Tue, 15 Feb 2022 14:22:45 -0800 Subject: [PATCH] fix(core): Use node's TCP ports when connecting to TCP relay Allows connecting to TCP relays that aren't acting as bootstrap nodes, and connecting to TCP relays that have different or additional TCP ports compared to UDP ports. --- src/core/core.cpp | 4 ++- src/core/dhtserver.cpp | 3 ++- src/core/dhtserver.h | 2 ++ src/net/bootstrapnodeupdater.cpp | 42 +++++++++++++++++++++++++------- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index a640ef3d5..c11718e28 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -846,7 +846,9 @@ void Core::bootstrapDht() PARSE_ERR(error); } if (dhtServer.statusTcp) { - tox_add_tcp_relay(tox.get(), address.constData(), dhtServer.udpPort, pkPtr, &error); + const auto ports = dhtServer.tcpPorts.size(); + const auto tcpPort = rand() % ports; + tox_add_tcp_relay(tox.get(), address.constData(), tcpPort, pkPtr, &error); PARSE_ERR(error); } diff --git a/src/core/dhtserver.cpp b/src/core/dhtserver.cpp index 083eab2fc..20b1689c5 100644 --- a/src/core/dhtserver.cpp +++ b/src/core/dhtserver.cpp @@ -33,7 +33,8 @@ bool DhtServer::operator==(const DhtServer& other) const && ipv6 == other.ipv6 && maintainer == other.maintainer && userId == other.userId - && udpPort == other.udpPort); + && udpPort == other.udpPort + && tcpPorts == other.tcpPorts); } /** diff --git a/src/core/dhtserver.h b/src/core/dhtserver.h index 3ab6f79a1..259a5e5f7 100644 --- a/src/core/dhtserver.h +++ b/src/core/dhtserver.h @@ -20,6 +20,7 @@ #pragma once #include +#include struct DhtServer { @@ -30,6 +31,7 @@ struct DhtServer QString maintainer; QString userId; quint16 udpPort; + std::vector tcpPorts; bool operator==(const DhtServer& other) const; bool operator!=(const DhtServer& other) const; diff --git a/src/net/bootstrapnodeupdater.cpp b/src/net/bootstrapnodeupdater.cpp index bd3555a57..601552559 100644 --- a/src/net/bootstrapnodeupdater.cpp +++ b/src/net/bootstrapnodeupdater.cpp @@ -29,6 +29,9 @@ #include #include #include +#include + +#include namespace NodeFields { const QLatin1String status_udp{"status_udp"}; @@ -38,9 +41,8 @@ const QLatin1String ipv6{"ipv6"}; const QLatin1String public_key{"public_key"}; const QLatin1String udp_port{"port"}; const QLatin1String maintainer{"maintainer"}; -// TODO(sudden6): make use of this field once we differentiate between TCP nodes, and bootstrap nodes const QLatin1String tcp_ports{"tcp_ports"}; -const QStringList neededFields{status_udp, status_tcp, ipv4, ipv6, public_key, udp_port, maintainer}; +const QStringList neededFields{status_udp, status_tcp, ipv4, ipv6, public_key, udp_port, tcp_ports, maintainer}; } // namespace NodeFields namespace { @@ -63,13 +65,22 @@ void jsonNodeToDhtServer(const QJsonObject& node, QList& outList) return; } - // only use nodes that provide at least UDP connection - if (!node[NodeFields::status_udp].toBool(false)) { - return; - } - const QString public_key = node[NodeFields::public_key].toString({}); const auto udp_port = node[NodeFields::udp_port].toInt(-1); + const auto status_udp = node[NodeFields::status_udp].toBool(false); + const auto status_tcp = node[NodeFields::status_tcp].toBool(false); + const QString maintainer = node[NodeFields::maintainer].toString({}); + + std::vector tcp_ports; + const auto jsonTcpPorts = node[NodeFields::tcp_ports].toArray(); + for (int i = 0; i < jsonTcpPorts.count(); ++i) { + const auto port = jsonTcpPorts.at(i).toInt(); + if (port < 1 || port > std::numeric_limits::max()) { + qDebug () << "Invalid TCP port in nodes list:" << port; + return; + } + tcp_ports.emplace_back(static_cast(port)); + } // nodes.tox.chat doesn't use empty strings for empty addresses QString ipv6_address = node[NodeFields::ipv6].toString({}); @@ -86,7 +97,13 @@ void jsonNodeToDhtServer(const QJsonObject& node, QList& outList) qWarning() << "Both ipv4 and ipv4 addresses are empty for" << public_key; } - const QString maintainer = node[NodeFields::maintainer].toString({}); + if (status_udp && udp_port == -1) { + qWarning() << "UDP enabled but no UDP port for" << public_key; + } + + if (status_tcp && tcp_ports.empty()) { + qWarning() << "TCP enabled but no TCP ports for:" << public_key; + } if (udp_port < 1 || udp_port > std::numeric_limits::max()) { qDebug() << "Invalid port in nodes list:" << udp_port; @@ -101,7 +118,8 @@ void jsonNodeToDhtServer(const QJsonObject& node, QList& outList) DhtServer server; server.statusUdp = true; - server.statusTcp = node[NodeFields::status_udp].toBool(false); + server.statusTcp = status_tcp; + server.tcpPorts = tcp_ports; server.userId = public_key; server.udpPort = udp_port_u16; server.maintainer = maintainer; @@ -167,6 +185,12 @@ QByteArray serialize(QList nodes) nodeJson.insert(NodeFields::public_key, node.userId); nodeJson.insert(NodeFields::udp_port, node.udpPort); nodeJson.insert(NodeFields::maintainer, node.maintainer); + + QJsonArray tcp_ports; + for (size_t i = 0; i < node.tcpPorts.size(); ++i) { + tcp_ports.push_back(node.tcpPorts.at(i)); + } + nodeJson.insert(NodeFields::tcp_ports, tcp_ports); jsonNodes.append(nodeJson); } QJsonObject rootObj;