Simple TCP Proxy Server

This commit is contained in:
Syping 2021-02-25 15:48:59 +01:00
commit 3dee85fc5d
4 changed files with 193 additions and 0 deletions

27
CMakeLists.txt Normal file
View file

@ -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)

97
src/main.cpp Normal file
View file

@ -0,0 +1,97 @@
#include "proxyserver.h"
#include <QCommandLineParser>
#include <QCommandLineOption>
#include <QCoreApplication>
#include <QJsonDocument>
#include <QJsonObject>
#include <QTextStream>
#include <QFile>
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();
}

47
src/proxyserver.cpp Normal file
View file

@ -0,0 +1,47 @@
#include "proxyserver.h"
#include <QTextStream>
#include <QTcpSocket>
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();
});
}

22
src/proxyserver.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef PROXYSERVER_H
#define PROXYSERVER_H
#include <QTcpServer>
#include <QObject>
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