commit 3dee85fc5d8a8d1270c819b5625431a2e50644b0 Author: Syping Date: Thu Feb 25 15:48:59 2021 +0100 Simple TCP Proxy Server diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..cae24f3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.7) + +project(proxylight LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(FORCE_QT_VERSION "" CACHE STRING "Force Qt Version") +if(FORCE_QT_VERSION) + set(QT_VERSION_MAJOR ${FORCE_QT_VERSION}) +else() + find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) +endif() +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network REQUIRED) + +add_executable(proxylight + src/main.cpp + src/proxyserver.cpp + src/proxyserver.h +) +target_link_libraries(proxylight Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Network) diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..c463704 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,97 @@ +#include "proxyserver.h" +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + app.setApplicationName("proxylight"); + app.setApplicationVersion("0.1"); + + QCommandLineParser commandLineParser; + commandLineParser.addHelpOption(); + commandLineParser.addVersionOption(); + commandLineParser.addPositionalArgument("config", "Configuration file."); + commandLineParser.process(app); + + const QStringList args = commandLineParser.positionalArguments(); + if (args.count() != 1) { + QTextStream(stderr) << "Configuration file not defined!" << Qt::endl; + return 1; + } + const QString configFile = args.at(0); + if (!QFile::exists(configFile)) { + QTextStream(stderr) << "Configuration file " << configFile << " not found!" << Qt::endl; + return 1; + } + + QFile configFileIO(configFile); + if (!configFileIO.open(QIODevice::ReadOnly)) { + QTextStream(stderr) << "Configuration file " << configFile << " can't be read!" << Qt::endl; + return 1; + } + else { + QTextStream(stderr) << "Configuration file " << configFile << " found!" << Qt::endl; + } + + const QByteArray configData = configFileIO.readAll(); + const QJsonDocument jsonDocument = QJsonDocument::fromJson(configData); + const QJsonObject jsonObject = jsonDocument.object(); + for (auto it = jsonObject.constBegin(); it != jsonObject.constEnd(); it++) { + const QJsonValue value = it.value(); + if (!value.isObject()) + break; + const QString serverName = it.key(); + int localPort = -1; + int remotePort = -1; + QString remoteHost; + const QJsonObject object = value.toObject(); + for (auto it = object.constBegin(); it != object.constEnd(); it++) { + const QString key = it.key(); + if (key == "LocalPort") { + const QJsonValue value = it.value(); + if (value.isDouble()) { + localPort = value.toInt(); + } + else if (value.isString()) { + bool ok; + localPort = value.toString().toInt(&ok); + } + } + if (key == "RemotePort") { + const QJsonValue value = it.value(); + if (value.isDouble()) { + remotePort = value.toInt(); + } + else if (value.isString()) { + bool ok; + remotePort = value.toString().toInt(&ok); + } + } + if (key == "RemoteHost") { + const QJsonValue value = it.value(); + if (value.isString()) { + remoteHost = value.toString(); + } + } + } + if (localPort == -1 || remotePort == -1 || remoteHost.isEmpty()) { + QTextStream(stderr) << serverName << ": Loading failed!" << Qt::endl; + break; + } + ProxyServer *proxyServer = new ProxyServer(localPort, remotePort, remoteHost, serverName); + if (!proxyServer->isListening()) { + QTextStream(stderr) << serverName << ": Binding failed!" << Qt::endl; + proxyServer->deleteLater(); + break; + } + QTextStream(stderr) << serverName << ": Proxy started!" << Qt::endl; + } + + return app.exec(); +} diff --git a/src/proxyserver.cpp b/src/proxyserver.cpp new file mode 100644 index 0000000..a92443b --- /dev/null +++ b/src/proxyserver.cpp @@ -0,0 +1,47 @@ +#include "proxyserver.h" +#include +#include + +ProxyServer::ProxyServer(int localPort, int remotePort, const QString &remoteHost, const QString &serverName) +{ + listen(QHostAddress::LocalHost, localPort); + p_remotePort = remotePort; + p_remoteHost = remoteHost; + p_serverName = serverName; +} + +void ProxyServer::incomingConnection(qintptr socketDescriptor) +{ + QTcpSocket *motherSocket = new QTcpSocket(this); + motherSocket->setSocketDescriptor(socketDescriptor); + motherSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1); + motherSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1); + + QTextStream(stderr) << p_serverName << ": " << motherSocket->peerAddress().toString() << " incoming connected!" << Qt::endl; + + QTcpSocket *childSocket = new QTcpSocket(this); + childSocket->connectToHost(p_remoteHost, p_remotePort); + childSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1); + childSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1); + QTextStream(stderr) << p_serverName << ": " << p_remoteHost << " outgoing connecting..." << Qt::endl; + + QObject::connect(motherSocket, &QTcpSocket::readyRead, this, [=](){ + childSocket->write(motherSocket->readAll()); + }); + QObject::connect(motherSocket, &QTcpSocket::disconnected, this, [=](){ + QTextStream(stderr) << p_serverName << ": " << motherSocket->peerAddress().toString() << " incoming disconnected!" << Qt::endl; + childSocket->disconnectFromHost(); + motherSocket->deleteLater(); + }); + QObject::connect(childSocket, &QTcpSocket::connected, this, [=](){ + QTextStream(stderr) << p_serverName << ": " << childSocket->peerAddress().toString() << " outgoing connected!" << Qt::endl; + }); + QObject::connect(childSocket, &QTcpSocket::readyRead, this, [=](){ + motherSocket->write(childSocket->readAll()); + }); + QObject::connect(childSocket, &QTcpSocket::disconnected, this, [=](){ + QTextStream(stderr) << p_serverName << ": " << childSocket->peerAddress().toString() << " outgoing disconnected!" << Qt::endl; + motherSocket->disconnectFromHost(); + childSocket->deleteLater(); + }); +} diff --git a/src/proxyserver.h b/src/proxyserver.h new file mode 100644 index 0000000..47fe32a --- /dev/null +++ b/src/proxyserver.h @@ -0,0 +1,22 @@ +#ifndef PROXYSERVER_H +#define PROXYSERVER_H + +#include +#include + +class ProxyServer : public QTcpServer +{ + Q_OBJECT +public: + ProxyServer(int localPort, int remotePort, const QString &remoteHost, const QString &serverName); + +protected: + void incomingConnection(qintptr socketDescriptor); + +private: + int p_remotePort; + QString p_remoteHost; + QString p_serverName; +}; + +#endif // PROXYSERVER_H