Simple TCP Proxy Server
This commit is contained in:
commit
3dee85fc5d
4 changed files with 193 additions and 0 deletions
27
CMakeLists.txt
Normal file
27
CMakeLists.txt
Normal 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
97
src/main.cpp
Normal 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
47
src/proxyserver.cpp
Normal 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
22
src/proxyserver.h
Normal 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
|
Loading…
Reference in a new issue