mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-20 02:00:55 +07:00
feat: per-tunnel ifname for WG service, UAPI pipe, and SCM for Windows
This commit is contained in:
@@ -37,11 +37,14 @@ int WindowsDaemonTunnel::run(QStringList& tokens) {
|
||||
QCoreApplication::setApplicationName("Amnezia VPN Tunnel");
|
||||
QCoreApplication::setApplicationVersion(Constants::versionString());
|
||||
|
||||
if (tokens.length() != 2) {
|
||||
logger.error() << "Expected 1 parameter only: the config file.";
|
||||
if (tokens.length() < 2 || tokens.length() > 3) {
|
||||
logger.error() << "Expected: <config> [<ifname>]";
|
||||
return 1;
|
||||
}
|
||||
QString maybeConfig = tokens.at(1);
|
||||
QString name = tokens.length() == 3 && !tokens.at(2).isEmpty()
|
||||
? tokens.at(2)
|
||||
: WireguardUtilsWindows::s_defaultInterfaceName();
|
||||
|
||||
if (!maybeConfig.startsWith("[Interface]")) {
|
||||
logger.error() << "parameter Does not seem to be a config";
|
||||
@@ -64,7 +67,6 @@ int WindowsDaemonTunnel::run(QStringList& tokens) {
|
||||
WindowsUtils::windowsLog("Failed to get WireGuardTunnelService function");
|
||||
return 1;
|
||||
}
|
||||
auto name = WireguardUtilsWindows::s_interfaceName();
|
||||
if (!tunnelProc(maybeConfig.utf16(), name.utf16())) {
|
||||
logger.error() << "Failed to activate the tunnel service";
|
||||
return 1;
|
||||
|
||||
@@ -15,9 +15,8 @@
|
||||
#include "platforms/windows/windowsutils.h"
|
||||
#include "windowsdaemon.h"
|
||||
|
||||
#define TUNNEL_NAMED_PIPE \
|
||||
"\\\\." \
|
||||
"\\pipe\\ProtectedPrefix\\Administrators\\AmneziaWG\\AmneziaVPN"
|
||||
#define TUNNEL_NAMED_PIPE_PREFIX \
|
||||
"\\\\.\\pipe\\ProtectedPrefix\\Administrators\\AmneziaWG\\"
|
||||
|
||||
constexpr uint32_t WINDOWS_TUNNEL_MONITOR_TIMEOUT_MSEC = 2000;
|
||||
|
||||
@@ -28,6 +27,10 @@ Logger logger("WindowsTunnelService");
|
||||
static bool stopAndDeleteTunnelService(SC_HANDLE service);
|
||||
static bool waitForServiceStatus(SC_HANDLE service, DWORD expectedStatus);
|
||||
|
||||
std::wstring WindowsTunnelService::serviceNameForIfname(const QString& ifname) {
|
||||
return (QStringLiteral("AmneziaWGTunnel$") + ifname).toStdWString();
|
||||
}
|
||||
|
||||
WindowsTunnelService::WindowsTunnelService(QObject* parent) : QObject(parent) {
|
||||
MZ_COUNT_CTOR(WindowsTunnelService);
|
||||
logger.debug() << "WindowsTunnelService created.";
|
||||
@@ -37,7 +40,7 @@ WindowsTunnelService::WindowsTunnelService(QObject* parent) : QObject(parent) {
|
||||
WindowsUtils::windowsLog("Failed to open SCManager");
|
||||
}
|
||||
|
||||
// Is the service already running? Terminate it.
|
||||
// Is the legacy single-tunnel service still around? Terminate it.
|
||||
SC_HANDLE service =
|
||||
OpenService((SC_HANDLE)m_scm, TUNNEL_SERVICE_NAME, SERVICE_ALL_ACCESS);
|
||||
if (service != nullptr) {
|
||||
@@ -108,8 +111,11 @@ void WindowsTunnelService::timeout() {
|
||||
emit backendFailure();
|
||||
}
|
||||
|
||||
bool WindowsTunnelService::start(const QString& configData) {
|
||||
logger.debug() << "Starting the tunnel service";
|
||||
bool WindowsTunnelService::start(const QString& configData, const QString& ifname) {
|
||||
logger.debug() << "Starting the tunnel service for" << ifname;
|
||||
|
||||
m_ifname = ifname;
|
||||
const std::wstring serviceName = serviceNameForIfname(ifname);
|
||||
|
||||
m_logworker = new WindowsTunnelLogger(WindowsCommons::tunnelLogFile());
|
||||
m_logworker->moveToThread(&m_logthread);
|
||||
@@ -128,10 +134,9 @@ bool WindowsTunnelService::start(const QString& configData) {
|
||||
m_logworker = nullptr;
|
||||
});
|
||||
|
||||
// Let's see if we have to delete a previous instance.
|
||||
service = OpenService(scm, TUNNEL_SERVICE_NAME, SERVICE_ALL_ACCESS);
|
||||
service = OpenService(scm, serviceName.c_str(), SERVICE_ALL_ACCESS);
|
||||
if (service) {
|
||||
logger.debug() << "An existing service has been detected. Let's close it.";
|
||||
logger.debug() << "A stale service was detected. Cleaning it up.";
|
||||
if (!stopAndDeleteTunnelService(service)) {
|
||||
return false;
|
||||
}
|
||||
@@ -143,12 +148,12 @@ bool WindowsTunnelService::start(const QString& configData) {
|
||||
{
|
||||
QTextStream out(&serviceCmdline);
|
||||
out << "\"" << qApp->applicationFilePath() << "\" tunneldaemon \""
|
||||
<< configData << "\"";
|
||||
<< configData << "\" \"" << ifname << "\"";
|
||||
}
|
||||
|
||||
logger.debug() << "Service:" << qApp->applicationFilePath();
|
||||
|
||||
service = CreateService(scm, TUNNEL_SERVICE_NAME, L"Amnezia VPN (tunnel)",
|
||||
service = CreateService(scm, serviceName.c_str(), L"Amnezia VPN (tunnel)",
|
||||
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
|
||||
SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
|
||||
(const wchar_t*)serviceCmdline.utf16(), nullptr, 0,
|
||||
@@ -236,8 +241,9 @@ static bool stopAndDeleteTunnelService(SC_HANDLE service) {
|
||||
}
|
||||
|
||||
QString WindowsTunnelService::uapiCommand(const QString& command) {
|
||||
// Create a pipe to the tunnel service.
|
||||
LPTSTR tunnelName = (LPTSTR)TEXT(TUNNEL_NAMED_PIPE);
|
||||
const std::wstring pipeName = std::wstring(TEXT(TUNNEL_NAMED_PIPE_PREFIX))
|
||||
+ m_ifname.toStdWString();
|
||||
LPCWSTR tunnelName = pipeName.c_str();
|
||||
HANDLE pipe = CreateFile(tunnelName, GENERIC_READ | GENERIC_WRITE, 0, nullptr,
|
||||
OPEN_EXISTING, 0, nullptr);
|
||||
if (pipe == INVALID_HANDLE_VALUE) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <string>
|
||||
|
||||
#include "windowstunnellogger.h"
|
||||
|
||||
@@ -20,11 +21,13 @@ class WindowsTunnelService final : public QObject {
|
||||
WindowsTunnelService(QObject* parent = nullptr);
|
||||
~WindowsTunnelService();
|
||||
|
||||
bool start(const QString& configData);
|
||||
bool start(const QString& configData, const QString& ifname);
|
||||
void stop();
|
||||
bool isRunning();
|
||||
QString uapiCommand(const QString& command);
|
||||
|
||||
static std::wstring serviceNameForIfname(const QString& ifname);
|
||||
|
||||
signals:
|
||||
void backendFailure();
|
||||
|
||||
@@ -36,6 +39,7 @@ class WindowsTunnelService final : public QObject {
|
||||
QTimer m_timer;
|
||||
QThread m_logthread;
|
||||
WindowsTunnelLogger* m_logworker = nullptr;
|
||||
QString m_ifname;
|
||||
|
||||
// These are really SC_HANDLEs in disguise.
|
||||
void* m_scm = nullptr;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "killswitch.h"
|
||||
#include "leakdetector.h"
|
||||
#include "logger.h"
|
||||
#include "windowsfirewall.h"
|
||||
@@ -110,15 +111,14 @@ bool WireguardUtilsWindows::addInterface(const InterfaceConfig& config) {
|
||||
configString.truncate(peerStart);
|
||||
}
|
||||
|
||||
if (!m_tunnel.start(configString)) {
|
||||
m_ifname = config.m_ifname.isEmpty() ? s_defaultInterfaceName() : config.m_ifname;
|
||||
if (!m_tunnel.start(configString, m_ifname)) {
|
||||
logger.error() << "Failed to activate the tunnel service";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine the interface LUID
|
||||
NET_LUID luid;
|
||||
const QString ifname = config.m_ifname.isEmpty() ? interfaceName() : config.m_ifname;
|
||||
DWORD result = ConvertInterfaceAliasToLuid((wchar_t*)ifname.utf16(), &luid);
|
||||
DWORD result = ConvertInterfaceAliasToLuid((wchar_t*)m_ifname.utf16(), &luid);
|
||||
if (result != 0) {
|
||||
logger.error() << "Failed to lookup LUID:" << result;
|
||||
return false;
|
||||
@@ -127,11 +127,11 @@ bool WireguardUtilsWindows::addInterface(const InterfaceConfig& config) {
|
||||
m_routeMonitor = new WindowsRouteMonitor(luid.Value, this);
|
||||
|
||||
if (config.m_killSwitchEnabled) {
|
||||
// Enable the windows firewall
|
||||
NET_IFINDEX ifindex;
|
||||
ConvertInterfaceLuidToIndex(&luid, &ifindex);
|
||||
m_firewall->allowAllTraffic();
|
||||
m_firewall->enableInterface(ifindex);
|
||||
KillSwitch::instance()->addAllowedRange({});
|
||||
}
|
||||
|
||||
logger.debug() << "Registration completed";
|
||||
|
||||
@@ -27,10 +27,8 @@ class WireguardUtilsWindows final : public WireguardUtils {
|
||||
~WireguardUtilsWindows();
|
||||
|
||||
bool interfaceExists() override { return m_tunnel.isRunning(); }
|
||||
QString interfaceName() override {
|
||||
return WireguardUtilsWindows::s_interfaceName();
|
||||
}
|
||||
static const QString s_interfaceName() { return "AmneziaVPN"; }
|
||||
QString interfaceName() override { return m_ifname; }
|
||||
static const QString s_defaultInterfaceName() { return "AmneziaVPN"; }
|
||||
bool addInterface(const InterfaceConfig& config) override;
|
||||
bool deleteInterface() override;
|
||||
|
||||
@@ -54,6 +52,7 @@ class WireguardUtilsWindows final : public WireguardUtils {
|
||||
void buildMibForwardRow(const IPAddress& prefix, void* row);
|
||||
|
||||
quint64 m_luid = 0;
|
||||
QString m_ifname;
|
||||
WindowsTunnelService m_tunnel;
|
||||
QPointer<WindowsRouteMonitor> m_routeMonitor;
|
||||
QPointer<WindowsFirewall> m_firewall;
|
||||
|
||||
Reference in New Issue
Block a user