Work on ssl socket fixes

This commit is contained in:
Simon Stürz 2021-08-05 15:52:03 +02:00
parent b9ebc345a5
commit f4b5fba91d
22 changed files with 398 additions and 21 deletions

View File

@ -1,5 +1,6 @@
include(../nymea-remoteproxy.pri)
include(../libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri)
include(../common/common.pri)
TARGET = nymea-remoteproxy-client
TEMPLATE = app

View File

@ -127,6 +127,9 @@ int main(int argc, char *argv[])
QCommandLineOption uuidOption(QStringList() << "uuid", "The uuid of the client. If not specified, a new one will be created", "uuid");
parser.addOption(uuidOption);
QCommandLineOption tcpOption(QStringList() << "tcp", "Use TCP as tronsport instead of web sockets.");
parser.addOption(tcpOption);
QCommandLineOption verboseOption(QStringList() << "verbose", "Print more information about the connection.");
parser.addOption(verboseOption);
@ -165,10 +168,17 @@ int main(int argc, char *argv[])
uuid = QUuid::createUuid();
}
ProxyClient client(parser.value(nameOption), uuid);
client.setInsecure(parser.isSet(insecureOption));
client.setPingpong(parser.isSet(pingPongOption));
client.start(serverUrl, parser.value(tokenOption), parser.value(nonceOption));
if (parser.isSet(tcpOption)) {
ProxyClient client(parser.value(nameOption), uuid, RemoteProxyConnection::ConnectionTypeTcpSocket);
client.setInsecure(parser.isSet(insecureOption));
client.setPingpong(parser.isSet(pingPongOption));
client.start(serverUrl, parser.value(tokenOption), parser.value(nonceOption));
} else {
ProxyClient client(parser.value(nameOption), uuid, RemoteProxyConnection::ConnectionTypeWebSocket);
client.setInsecure(parser.isSet(insecureOption));
client.setPingpong(parser.isSet(pingPongOption));
client.start(serverUrl, parser.value(tokenOption), parser.value(nonceOption));
}
return application.exec();
}

View File

@ -31,12 +31,12 @@
Q_LOGGING_CATEGORY(dcProxyClient, "ProxyClient")
ProxyClient::ProxyClient(const QString &name, const QUuid &uuid, QObject *parent) :
ProxyClient::ProxyClient(const QString &name, const QUuid &uuid, RemoteProxyConnection::ConnectionType connectionType, QObject *parent) :
QObject(parent),
m_name(name),
m_uuid(uuid)
{
m_connection = new RemoteProxyConnection(m_uuid, m_name, this);
m_connection = new RemoteProxyConnection(m_uuid, m_name, connectionType, this);
qCDebug(dcProxyClient()) << "Creating remote proxy connection" << m_name << m_uuid.toString();
connect(m_connection, &RemoteProxyConnection::ready, this, &ProxyClient::onClientReady);
connect(m_connection, &RemoteProxyConnection::authenticated, this, &ProxyClient::onAuthenticationFinished);

View File

@ -41,7 +41,7 @@ class ProxyClient : public QObject
{
Q_OBJECT
public:
explicit ProxyClient(const QString &name, const QUuid &uuid, QObject *parent = nullptr);
explicit ProxyClient(const QString &name, const QUuid &uuid, RemoteProxyConnection::ConnectionType connectionType, QObject *parent = nullptr);
void setInsecure(bool insecure);
void setPingpong(bool enable);

View File

@ -1,4 +1,4 @@
INCLUDEPATH += $$PWD
#INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/slipdataprocessor.h

9
debian/control vendored
View File

@ -55,6 +55,15 @@ Description: The nymea remote proxy client for testing
The nymea remote proxy client for testing
Package: nymea-remoteproxy-tunnelclient
Architecture: any
Section: libs
Depends: ${shlibs:Depends},
${misc:Depends},
Description: The nymea remote proxy tunnel client for testing
The nymea remote proxy tunnel client for testing
Package: libnymea-remoteproxyclient
Architecture: any
Section: libs

View File

@ -0,0 +1 @@
usr/bin/nymea-remoteproxy-tunnelclient

View File

@ -151,11 +151,21 @@ void SslServer::incomingConnection(qintptr socketDescriptor)
qCDebug(dcTcpSocketServer()) << "Incomming connection" << sslSocket;
connect(sslSocket, &QSslSocket::readyRead, this, &SslServer::onSocketReadyRead);
connect(sslSocket, &QSslSocket::disconnected, this, &SslServer::onClientDisconnected);
connect(sslSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError)));
connect(sslSocket, &QSslSocket::encrypted, this, [this, sslSocket](){
qCDebug(dcTcpSocketServer()) << "SSL encryption established for" << sslSocket;
emit clientConnected(sslSocket);
});
typedef void (QSslSocket:: *sslErrorsSignal)(const QList<QSslError> &);
connect(sslSocket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors), this, [](const QList<QSslError> &errors) {
qCWarning(dcTcpSocketServer()) << "SSL Errors happened in the client connections:";
foreach (const QSslError &error, errors) {
qCWarning(dcTcpSocketServer()) << "SSL Error:" << error.error() << error.errorString();
}
});
if (!sslSocket->setSocketDescriptor(socketDescriptor)) {
qCWarning(dcTcpSocketServer()) << "Failed to set SSL socket descriptor.";
delete sslSocket;
@ -163,8 +173,9 @@ void SslServer::incomingConnection(qintptr socketDescriptor)
}
if (m_sslEnabled) {
sslSocket->setSslConfiguration(m_config);
qCDebug(dcTcpSocketServer()) << "Start SSL encryption for" << sslSocket;
sslSocket->setSslConfiguration(m_config);
addPendingConnection(sslSocket);
sslSocket->startServerEncryption();
} else {
emit clientConnected(sslSocket);
@ -187,4 +198,9 @@ void SslServer::onSocketReadyRead()
emit dataAvailable(sslSocket, data);
}
void SslServer::onSocketError(QAbstractSocket::SocketError error)
{
qCWarning(dcTcpSocketServer()) << "Socket error occured" << error;
}
}

View File

@ -60,6 +60,7 @@ protected:
private slots:
void onClientDisconnected();
void onSocketReadyRead();
void onSocketError(QAbstractSocket::SocketError);
};

View File

@ -1,3 +1,5 @@
include(../common/common.pri)
INCLUDEPATH += $$PWD
HEADERS += \

View File

@ -4,10 +4,13 @@ TEMPLATE = lib
TARGET = nymea-remoteproxyclient
target.path = $$[QT_INSTALL_LIBS]
include(../common/common.pri)
include(libnymea-remoteproxyclient.pri)
installheaders.files = remoteproxyconnection.h
installheaders.files = \
remoteproxyconnection.h \
tunnelproxy/tunnelproxyremoteconnection.h \
tunnelproxy/tunnelproxysocket.h \
tcpsocketconnection.h
installheaders.path = $$[QT_INSTALL_PREFIX]/include/nymea-remoteproxyclient/
INSTALLS += target installheaders

View File

@ -39,9 +39,11 @@ TcpSocketConnection::TcpSocketConnection(QObject *parent) :
connect(m_tcpSocket, &QSslSocket::disconnected, this, &TcpSocketConnection::onDisconnected);
connect(m_tcpSocket, &QSslSocket::encrypted, this, &TcpSocketConnection::onEncrypted);
connect(m_tcpSocket, &QSslSocket::readyRead, this, &TcpSocketConnection::onReadyRead);
connect(m_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
connect(m_tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onStateChanged(QAbstractSocket::SocketState)));
connect(m_tcpSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SIGNAL(sslErrors(QList<QSslError>)));
typedef void (QSslSocket:: *errorSignal)(QAbstractSocket::SocketError);
connect(m_tcpSocket, static_cast<errorSignal>(&QSslSocket::error), this, &TcpSocketConnection::onError);
connect(m_tcpSocket, &QSslSocket::stateChanged, this, &TcpSocketConnection::onStateChanged);
typedef void (QSslSocket:: *sslErrorsSignal)(const QList<QSslError> &);
QObject::connect(m_tcpSocket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors), this, &TcpSocketConnection::sslErrors);
}
TcpSocketConnection::~TcpSocketConnection()
@ -109,12 +111,12 @@ void TcpSocketConnection::onReadyRead()
void TcpSocketConnection::connectServer(const QUrl &serverUrl)
{
setServerUrl(serverUrl);
qCDebug(dcRemoteProxyClientTcpSocket()) << "Connecting to" << this->serverUrl().toString();
if (serverUrl.scheme() == "tcp") {
qCDebug(dcRemoteProxyClientTcpSocket()) << "Connecting to" << this->serverUrl().toString();
m_tcpSocket->connectToHost(QHostAddress(this->serverUrl().host()), static_cast<quint16>(this->serverUrl().port()));
} else {
m_ssl = true;
qCDebug(dcRemoteProxyClientTcpSocket()) << "Connecting encrypted to" << this->serverUrl().toString();
m_tcpSocket->connectToHostEncrypted(this->serverUrl().host(), static_cast<quint16>(this->serverUrl().port()));
}
}

View File

@ -30,7 +30,7 @@
#include "tcpsocketconnection.h"
#include "websocketconnection.h"
#include "proxyjsonrpcclient.h"
#include "../common/slipdataprocessor.h"
#include "../../common/slipdataprocessor.h"
Q_LOGGING_CATEGORY(dcTunnelProxySocketServer, "dcTunnelProxySocketServer")
Q_LOGGING_CATEGORY(dcTunnelProxySocketServerTraffic, "dcTunnelProxySocketServerTraffic")

View File

@ -1,7 +1,7 @@
include(nymea-remoteproxy.pri)
TEMPLATE=subdirs
SUBDIRS += server client libnymea-remoteproxy libnymea-remoteproxyclient
SUBDIRS += server client tunnelclient libnymea-remoteproxy libnymea-remoteproxyclient
!disabletests {
SUBDIRS += tests
@ -13,6 +13,7 @@ SUBDIRS += server client libnymea-remoteproxy libnymea-remoteproxyclient
server.depends = libnymea-remoteproxy
client.depends = libnymea-remoteproxyclient
tunnelclient.depends = libnymea-remoteproxyclient
tests.depends = libnymea-remoteproxy libnymea-remoteproxyclient
test.commands = LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$$top_builddir/libnymea-remoteproxy:$$top_builddir/libnymea-remoteproxyclient \

View File

@ -923,7 +923,6 @@ void RemoteProxyTestsTunnelProxy::tunnelProxyEndToEndTest()
QVERIFY(receivedTestData2 == testData2);
// ** Remote connection 2 **
QString clientTwoName = "Client two";
@ -978,7 +977,6 @@ void RemoteProxyTestsTunnelProxy::tunnelProxyEndToEndTest()
QVERIFY(!remoteConnectionOne->remoteConnected());
QVERIFY(!remoteConnectionTwo->remoteConnected());
// Clean up
tunnelProxyServer->deleteLater();
remoteConnectionOne->deleteLater();

View File

@ -1,6 +1,6 @@
RESOURCES += ../resources/resources.qrc
include(../common/common.pri)
include(../../common/common.pri)
CONFIG += testcase
QT += testlib

View File

@ -0,0 +1,6 @@
#include "clientconnection.h"
ClientConnection::ClientConnection(QObject *parent) : QObject(parent)
{
}

View File

@ -0,0 +1,16 @@
#ifndef CLIENTCONNECTION_H
#define CLIENTCONNECTION_H
#include <QObject>
class ClientConnection : public QObject
{
Q_OBJECT
public:
explicit ClientConnection(QObject *parent = nullptr);
signals:
};
#endif // CLIENTCONNECTION_H

218
tunnelclient/main.cpp Normal file
View File

@ -0,0 +1,218 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by copyright law, and
* remains the property of nymea GmbH. All rights, including reproduction, publication,
* editing and translation, are reserved. The use of this project is subject to the terms of a
* license agreement to be concluded with nymea GmbH in accordance with the terms
* of use of nymea GmbH, available under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under
* the terms of the GNU General Public License as published by the Free Software Foundation,
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this project.
* If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under contact@nymea.io
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <QUrl>
#include <QUuid>
#include <QHash>
#include <QCoreApplication>
#include <QLoggingCategory>
#include <QCommandLineParser>
#include <QCommandLineOption>
#include "serverconnection.h"
#include "clientconnection.h"
static QHash<QString, bool> s_loggingFilters;
static const char *const normal = "\033[0m";
static const char *const warning = "\e[33m";
static const char *const error = "\e[31m";
static void loggingCategoryFilter(QLoggingCategory *category)
{
if (s_loggingFilters.contains(category->categoryName())) {
bool debugEnabled = s_loggingFilters.value(category->categoryName());
category->setEnabled(QtDebugMsg, debugEnabled);
category->setEnabled(QtWarningMsg, debugEnabled || s_loggingFilters.value("Warnings"));
} else {
// Enable default debug output
category->setEnabled(QtDebugMsg, true);
category->setEnabled(QtWarningMsg, s_loggingFilters.value("qml") || s_loggingFilters.value("Warnings"));
}
}
static void consoleLogHandler(QtMsgType type, const QMessageLogContext& context, const QString& message)
{
switch (type) {
case QtInfoMsg:
fprintf(stdout, "%s: %s\n", context.category, message.toUtf8().data());
break;
case QtDebugMsg:
fprintf(stdout, "%s: %s\n", context.category, message.toUtf8().data());
break;
case QtWarningMsg:
fprintf(stdout, "%s%s: %s%s\n", warning, context.category, message.toUtf8().data(), normal);
break;
case QtCriticalMsg:
fprintf(stdout, "%s%s: %s%s\n", error, context.category, message.toUtf8().data(), normal);
break;
case QtFatalMsg:
fprintf(stdout, "%s%s: %s%s\n", error, context.category, message.toUtf8().data(), normal);
break;
}
fflush(stdout);
}
int main(int argc, char *argv[])
{
qInstallMessageHandler(consoleLogHandler);
QCoreApplication application(argc, argv);
application.setApplicationName(SERVER_NAME_STRING);
application.setOrganizationName("nymea");
application.setApplicationVersion(SERVER_VERSION_STRING);
// Default debug categories
s_loggingFilters.insert("ProxyClient", true);
s_loggingFilters.insert("RemoteProxyClientJsonRpc", false);
s_loggingFilters.insert("RemoteProxyClientWebSocket", false);
s_loggingFilters.insert("RemoteProxyClientConnection", false);
s_loggingFilters.insert("RemoteProxyClientJsonRpcTraffic", false);
s_loggingFilters.insert("RemoteProxyClientConnectionTraffic", false);
QCommandLineParser parser;
parser.addHelpOption();
parser.addVersionOption();
parser.setApplicationDescription(QString("\nThe nymea remote proxy tunnel client application. This application allowes to register as client"
"or server on the tunnel proxy interface.\n\n"
"Version: %1\n"
"API version: %2\n\n"
"Copyright %3 2021 nymea GmbH <developer@nymea.io>\n")
.arg(SERVER_VERSION_STRING)
.arg(API_VERSION_STRING)
.arg(QChar(0xA9)));
QCommandLineOption urlOption(QStringList() << "u" << "url", "The proxy server url. Default ssl://dev-remoteproxy.nymea.io:2213", "url");
urlOption.setDefaultValue("ssl://dev-remoteproxy.nymea.io:2213");
parser.addOption(urlOption);
QCommandLineOption insecureOption(QStringList() << "i" << "igore-ssl", "Ignore SSL certificate errors.");
parser.addOption(insecureOption);
QCommandLineOption serverOption(QStringList() << "s" << "server", "Connect as tunnel proxy server connection.");
parser.addOption(serverOption);
QCommandLineOption clientOption(QStringList() << "c" << "client", "Connect as tunnel proxy client connection. The server uuid is required.");
parser.addOption(clientOption);
QCommandLineOption nameOption(QStringList() << "n" << "name", "The name of the connecting client.", "name");
parser.addOption(nameOption);
QCommandLineOption uuidOption(QStringList() << "u" << "uuid", "The uuid of the connecting client. If not specified, a new one will be created", "uuid");
parser.addOption(uuidOption);
QCommandLineOption serverUuidOption(QStringList() << "server-uuid", "The uuid of the server you want to connect to as client connection.");
parser.addOption(serverUuidOption);
QCommandLineOption verboseOption(QStringList() << "verbose", "Print more information about the connection.");
parser.addOption(verboseOption);
QCommandLineOption veryVerboseOption(QStringList() << "very-verbose", "Print the complete traffic information from the connection.");
parser.addOption(veryVerboseOption);
parser.process(application);
// Make sure not server and client given
if (parser.isSet(serverOption) && parser.isSet(clientOption)) {
qCritical() << "Please specify either beeing a client or a server connection, not both.";
exit(EXIT_FAILURE);
}
// Get the uuid to pick for the connection
QUuid uuid(parser.value(uuidOption));
if (uuid.isNull()) {
uuid = QUuid::createUuid();
qDebug() << "Picking automatic UUID" << uuid.toString();
}
QUrl serverUrl(parser.value(urlOption));
if (!serverUrl.isValid()) {
qCritical() << "Invalid proxy server url passed." << parser.value(urlOption);
exit(-1);
}
// Server, or if not specified server too
if (parser.isSet(serverOption) || (!parser.isSet(serverOption) && !parser.isSet(clientOption))) {
QString name = parser.value("name");
if (name.isEmpty()) {
name = "Server connection";
qDebug() << "Picking automatic name" << name;
}
// Enable verbose
if (parser.isSet(verboseOption) || parser.isSet(veryVerboseOption)) {
s_loggingFilters["default"] = true;
s_loggingFilters["TunnelProxySocketServer"] = true;
s_loggingFilters["RemoteProxyClientJsonRpc"] = true;
s_loggingFilters["RemoteProxyClientWebSocket"] = true;
s_loggingFilters["RemoteProxyClientConnection"] = true;
}
// Enable very verbose
if (parser.isSet(veryVerboseOption)) {
s_loggingFilters["RemoteProxyClientJsonRpcTraffic"] = true;
s_loggingFilters["TunnelProxySocketServerTraffic"] = true;
}
QLoggingCategory::installFilter(loggingCategoryFilter);
// Create the server connection
ServerConnection server(serverUrl, name, uuid, parser.isSet(insecureOption));
server.startServer();
} else {
// Client
QString name = parser.value("name");
if (name.isEmpty()) {
name = "Client connection";
qDebug() << "Picking automatic name" << name;
}
if (!parser.isSet(serverUuidOption)) {
qCritical() << "Please specify the server UUID you want to connect to using the --server-uuid parameter.";
exit(EXIT_FAILURE);
}
// Enable verbose
if (parser.isSet(verboseOption) || parser.isSet(veryVerboseOption)) {
s_loggingFilters["default"] = true;
s_loggingFilters["TunnelProxyRemoteConnection"] = true;
s_loggingFilters["RemoteProxyClientJsonRpc"] = true;
s_loggingFilters["RemoteProxyClientWebSocket"] = true;
s_loggingFilters["RemoteProxyClientConnection"] = true;
}
// Enable very verbose
if (parser.isSet(veryVerboseOption)) {
s_loggingFilters["RemoteProxyClientJsonRpcTraffic"] = true;
s_loggingFilters["TunnelProxySocketServerTraffic"] = true;
}
QLoggingCategory::installFilter(loggingCategoryFilter);
}
return application.exec();
}

View File

@ -0,0 +1,45 @@
#include "serverconnection.h"
ServerConnection::ServerConnection(const QUrl &serverUrl, const QString &name, const QUuid &uuid, bool insecure, QObject *parent) :
QObject(parent),
m_serverUrl(serverUrl),
m_name(name),
m_uuid(uuid),
m_insecure(insecure)
{
m_socketServer = new TunnelProxySocketServer(m_uuid, m_name, this);
connect(m_socketServer, &TunnelProxySocketServer::clientConnected, this, [=](TunnelProxySocket *tunnelProxySocket){
qDebug() << "[+] Client connected" << tunnelProxySocket;
});
connect(m_socketServer, &TunnelProxySocketServer::clientDisconnected, this, [=](TunnelProxySocket *tunnelProxySocket){
qDebug() << "[-] Client disconnected" << tunnelProxySocket;
});
connect(m_socketServer, &TunnelProxySocketServer::runningChanged, this, [=](bool running){
qDebug() << "--> Server is" << (running ? "running" : "not running any more");
if (running) {
qDebug() << "--> Connected with" << m_socketServer->remoteProxyServer() << m_socketServer->remoteProxyServerName() << m_socketServer->remoteProxyServerVersion() << m_socketServer->remoteProxyApiVersion();
}
});
connect(m_socketServer, &TunnelProxySocketServer::sslErrors, this, [=](const QList<QSslError> &errors){
if (m_insecure) {
qDebug() << "SSL errors occured. Ignoring because explicit specified.";
m_socketServer->ignoreSslErrors();
} else {
qWarning() << "SSL errors occured:";
foreach (const QSslError &sslError, errors) {
qWarning() << " --> " << sslError.errorString();
}
}
});
}
void ServerConnection::startServer()
{
m_socketServer->startServer(m_serverUrl);
}

View File

@ -0,0 +1,28 @@
#ifndef SERVERCONNECTION_H
#define SERVERCONNECTION_H
#include <QUuid>
#include <QObject>
#include "tunnelproxy/tunnelproxysocketserver.h"
using namespace remoteproxyclient;
class ServerConnection : public QObject
{
Q_OBJECT
public:
explicit ServerConnection(const QUrl &serverUrl, const QString &name, const QUuid &uuid, bool insecure, QObject *parent = nullptr);
void startServer();
private:
QUrl m_serverUrl;
QString m_name;
QUuid m_uuid;
bool m_insecure = false;
TunnelProxySocketServer *m_socketServer = nullptr;
};
#endif // SERVERCONNECTION_H

View File

@ -0,0 +1,20 @@
include(../nymea-remoteproxy.pri)
include(../libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri)
TARGET = nymea-remoteproxy-tunnelclient
TEMPLATE = app
INCLUDEPATH += ../libnymea-remoteproxy
LIBS += -L$$top_builddir/libnymea-remoteproxyclient/ -lnymea-remoteproxyclient
SOURCES += main.cpp \
clientconnection.cpp \
serverconnection.cpp
target.path = $$[QT_INSTALL_PREFIX]/bin
INSTALLS += target
HEADERS += \
clientconnection.h \
serverconnection.h