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