Skip to content

Commit

Permalink
VPN-6626: Install socks proxy as a service (#9952)
Browse files Browse the repository at this point in the history
* Add curlpipe tool to test named pipe support on Windows
* Add code to set our own Windows firewall rules
* Implement Windows service thread
* Add file logging when started as a service
* Install the socks proxy as a Windows service
* Split log levels and always write debug to file
* Add logfile option to enable logging manually
* Add WFP policy to restrict proxy access only to browsers
* Split windows firewall stuff into its own class
* Install socksproxy as a systemd service
* Install/enable/start proxy service on debian installation
* Add proxy service assets to RPM package too
* Automatically start proxy on installation
* Add a WinFwPolicy::create() method to handle WFP setup failure
* Don't install systemd service in containerized environment
  • Loading branch information
oskirby authored Nov 13, 2024
1 parent b2f942d commit 62cc6b9
Show file tree
Hide file tree
Showing 21 changed files with 1,104 additions and 173 deletions.
32 changes: 26 additions & 6 deletions extension/socks5proxy/bin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

qt_add_executable(socksproxy
main.cpp
verboselogger.cpp
verboselogger.h
sockslogger.cpp
sockslogger.h
)

target_link_libraries(socksproxy PUBLIC
Expand All @@ -15,15 +15,23 @@ target_link_libraries(socksproxy PUBLIC
)

if(WIN32)
target_compile_definitions(socksproxy PRIVATE PROXY_OS_WIN)
target_sources(socksproxy PRIVATE
windowsbypass.cpp
windowsbypass.h)
windowsbypass.h
winfwpolicy.cpp
winfwpolicy.h
winsvcthread.cpp
winsvcthread.h
winutils.cpp
winutils.h)
target_link_libraries(socksproxy PRIVATE Iphlpapi.lib)

install(FILES
${CMAKE_CURRENT_BINARY_DIR}/socksproxy.exe
DESTINATION .)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
target_compile_definitions(socksproxy PRIVATE PROXY_OS_LINUX)
target_sources(socksproxy PRIVATE
linuxbypass.cpp
linuxbypass.h)
Expand All @@ -32,9 +40,21 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
pkg_check_modules(LIBCAP REQUIRED IMPORTED_TARGET libcap)
target_link_libraries(socksproxy PRIVATE PkgConfig::LIBCAP)

# TODO: not install that yet.
#install(FILES ${CMAKE_CURRENT_BINARY_DIR}/socksproxy
# DESTINATION ${CMAKE_INSTALL_DATADIR}/socksproxy)
# Install a Systemd service to run the proxy, if supported.
pkg_check_modules(SYSTEMD systemd)
if("${SYSTEMD_FOUND}" EQUAL 1)
pkg_get_variable(SYSTEMD_UNIT_DIR systemd systemdsystemunitdir)
elseif(NOT DEFINED ENV{container})
set(SYSTEMD_UNIT_DIR /lib/systemd/system)
endif()
if(SYSTEMD_UNIT_DIR)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/socksproxy.service.in
${CMAKE_CURRENT_BINARY_DIR}/socksproxy.service)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/socksproxy.service
DESTINATION ${SYSTEMD_UNIT_DIR})
endif()

install(TARGETS socksproxy)
else()
# TODO: This is currently pointless on macos,
# so no point in shipping it.
Expand Down
80 changes: 66 additions & 14 deletions extension/socks5proxy/bin/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,23 @@

#include <QCommandLineParser>
#include <QCoreApplication>
#include <QDir>
#include <QLocalServer>
#include <QRandomGenerator>
#include <QStandardPaths>
#include <QString>
#include <QTcpServer>
#include <QTimer>

#include "socks5.h"
#include "verboselogger.h"
#include "sockslogger.h"

#ifdef __linux__
#if defined(PROXY_OS_LINUX)
# include "linuxbypass.h"
#endif
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#elif defined(PROXY_OS_WIN)
# include "windowsbypass.h"
# include "winfwpolicy.h"
# include "winsvcthread.h"
#endif

struct CliOptions {
Expand All @@ -27,6 +30,10 @@ struct CliOptions {
QString username = {};
QString password = {};
bool verbose = false;
bool logfile = false;
#if defined(PROXY_OS_WIN)
bool service = false;
#endif
};

static CliOptions parseArgs(const QCoreApplication& app) {
Expand All @@ -48,11 +55,25 @@ static CliOptions parseArgs(const QCoreApplication& app) {
QCommandLineOption passOption({"P", "password"}, "The password", "password");
parser.addOption(passOption);

QCommandLineOption localOption({"l", "local"}, "Local socket name", "name");
#if defined(PROXY_OS_WIN)
QCommandLineOption localOption({"n", "pipe"}, "SOCKS proxy over named pipe",
"name");
#else
QCommandLineOption localOption({"n", "unix"},
"SOCKS proxy over UNIX domain socket", "path");
#endif
parser.addOption(localOption);

QCommandLineOption logfileOption({"l", "logfile"}, "Save logs to file");
parser.addOption(logfileOption);

QCommandLineOption verboseOption({"v", "verbose"}, "Verbose");
parser.addOption(verboseOption);

#if defined(PROXY_OS_WIN)
QCommandLineOption serviceOption({"s", "service"}, "Windows service mode");
parser.addOption(serviceOption);
#endif
parser.process(app);

CliOptions out = {};
Expand All @@ -77,9 +98,19 @@ static CliOptions parseArgs(const QCoreApplication& app) {
if (parser.isSet(localOption)) {
out.localSocketName = parser.value(localOption);
}
if (parser.isSet(logfileOption)) {
out.logfile = true;
}
if (parser.isSet(verboseOption)) {
out.verbose = true;
}
#if defined(PROXY_OS_WIN)
if (parser.isSet(serviceOption)) {
out.service = true;
// Enforce logging when started as a service.
out.logfile = true;
}
#endif
return out;
};

Expand All @@ -95,10 +126,29 @@ int main(int argc, char** argv) {
return 1;
}

auto* logger = new SocksLogger(&app);
logger->setVerbose(config.verbose);
if (config.logfile) {
auto location = QStandardPaths::AppLocalDataLocation;
QDir logdir(QStandardPaths::writableLocation(location));
logger->setLogfile(logdir.filePath("socksproxy.log"));
}

#if defined(PROXY_OS_WIN)
if (config.service) {
WinSvcThread* svc = new WinSvcThread("Mozilla VPN Proxy");
svc->start();
}
#endif

Socks5* socks5;
if (!config.localSocketName.isEmpty()) {
QLocalServer* server = new QLocalServer();
QLocalServer* server = new QLocalServer(&app);
QObject::connect(&app, &QCoreApplication::aboutToQuit, server,
&QLocalServer::close);

socks5 = new Socks5(server);
server->setSocketOptions(QLocalServer::WorldAccessOption);
if (server->listen(config.localSocketName)) {
qDebug() << "Starting on local socket" << server->fullServerName();
} else if ((server->serverError() == QAbstractSocket::AddressInUseError) &&
Expand All @@ -112,24 +162,26 @@ int main(int argc, char** argv) {
return 1;
}
} else {
QTcpServer* server = new QTcpServer();
QTcpServer* server = new QTcpServer(&app);
QObject::connect(&app, &QCoreApplication::aboutToQuit, server,
&QTcpServer::close);

socks5 = new Socks5(server);
if (server->listen(config.addr, config.port)) {
qDebug() << "Starting on port" << config.port;
qDebug() << "Starting on port" << server->serverPort();
} else {
qWarning() << "Unable to listen to the proxy port" << config.port;
return 1;
}
}
QObject::connect(socks5, &Socks5::incomingConnection, logger,
&SocksLogger::incomingConnection);

if (config.verbose) {
new VerboseLogger(socks5);
}

#ifdef __linux__
#if defined(PROXY_OS_LINUX)
new LinuxBypass(socks5);
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#elif defined(PROXY_OS_WIN)
new WindowsBypass(socks5);
WinFwPolicy::create(socks5);
#endif

return app.exec();
Expand Down
Loading

0 comments on commit 62cc6b9

Please sign in to comment.