Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VPN-4227: Windows daemon recovery on crash #9214

Merged
merged 7 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 5 additions & 18 deletions src/daemon/daemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ bool Daemon::activate(const InterfaceConfig& config) {
return false;
}

if (supportDnsUtils() && !dnsutils()->restoreResolvers()) {
if (!dnsutils()->restoreResolvers()) {
return false;
}

Expand Down Expand Up @@ -161,10 +161,6 @@ bool Daemon::activate(const InterfaceConfig& config) {
}

bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) {
if (!supportDnsUtils()) {
return true;
}

if ((config.m_hopType == InterfaceConfig::MultiHopExit) ||
(config.m_hopType == InterfaceConfig::SingleHop)) {
QList<QHostAddress> resolvers;
Expand Down Expand Up @@ -348,13 +344,8 @@ bool Daemon::deactivate(bool emitSignals) {
}

// Cleanup DNS
if (supportDnsUtils() && !dnsutils()->restoreResolvers()) {
return false;
}

if (!wgutils()->interfaceExists()) {
logger.warning() << "Wireguard interface does not exist.";
return false;
if (!dnsutils()->restoreResolvers()) {
logger.warning() << "Failed to restore DNS resolvers.";
}

// Cleanup peers and routing
Expand All @@ -366,14 +357,10 @@ bool Daemon::deactivate(bool emitSignals) {
}
wgutils()->deletePeer(config);
}
m_connections.clear();

// Delete the interface
if (!wgutils()->deleteInterface()) {
return false;
}

m_connections.clear();
return true;
return wgutils()->deleteInterface();
}

QString Daemon::logs() {
Expand Down
1 change: 0 additions & 1 deletion src/daemon/daemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ class Daemon : public QObject {
virtual WireguardUtils* wgutils() const = 0;
virtual bool supportIPUtils() const { return false; }
virtual IPUtils* iputils() { return nullptr; }
virtual bool supportDnsUtils() const { return false; }
virtual DnsUtils* dnsutils() { return nullptr; }

static bool parseStringList(const QJsonObject& obj, const QString& name,
Expand Down
2 changes: 1 addition & 1 deletion src/localsocketcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ LocalSocketController::LocalSocketController() {
connect(m_socket, &QLocalSocket::connected, this,
&LocalSocketController::daemonConnected);
connect(m_socket, &QLocalSocket::disconnected, this,
&LocalSocketController::disconnected);
[&] { errorOccurred(QLocalSocket::PeerClosedError); });
connect(m_socket, &QLocalSocket::errorOccurred, this,
&LocalSocketController::errorOccurred);
connect(m_socket, &QLocalSocket::readyRead, this,
Expand Down
1 change: 0 additions & 1 deletion src/platforms/linux/daemon/dbusservice.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ class DBusService final : public Daemon, protected QDBusContext {
WireguardUtils* wgutils() const override { return m_wgutils; }
bool supportIPUtils() const override { return true; }
IPUtils* iputils() override;
bool supportDnsUtils() const override { return true; }
DnsUtils* dnsutils() override;

private:
Expand Down
1 change: 0 additions & 1 deletion src/platforms/macos/daemon/macosdaemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ class MacOSDaemon final : public Daemon {

protected:
WireguardUtils* wgutils() const override { return m_wgutils; }
bool supportDnsUtils() const override { return true; }
DnsUtils* dnsutils() override { return m_dnsutils; }
bool supportIPUtils() const override { return true; }
IPUtils* iputils() override { return m_iputils; }
Expand Down
56 changes: 31 additions & 25 deletions src/platforms/windows/daemon/dnsutilswindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@

#include "dnsutilswindows.h"

#include <WS2tcpip.h>
#include <iphlpapi.h>
#include <windows.h>
#include <winsock2.h>
#include <ws2ipdef.h>

#include <QProcess>
#include <QTextStream>
Expand Down Expand Up @@ -39,30 +42,27 @@ DnsUtilsWindows::~DnsUtilsWindows() {

bool DnsUtilsWindows::updateResolvers(const QString& ifname,
const QList<QHostAddress>& resolvers) {
NET_LUID luid;
if (ConvertInterfaceAliasToLuid((wchar_t*)ifname.utf16(), &luid) != 0) {
MIB_IF_ROW2 entry;
if (ConvertInterfaceAliasToLuid((wchar_t*)ifname.utf16(),
&entry.InterfaceLuid) != 0) {
logger.error() << "Failed to resolve LUID for" << ifname;
return false;
}
m_luid = luid.Value;
if (GetIfEntry2(&entry) != NO_ERROR) {
logger.error() << "Failed to resolve interface for" << ifname;
return false;
}
m_luid = entry.InterfaceLuid.Value;

logger.debug() << "Configuring DNS for" << ifname;
if (m_setInterfaceDnsSettingsProcAddr == nullptr) {
return updateResolversNetsh(resolvers);
return updateResolversNetsh(entry.InterfaceIndex, resolvers);
}
return updateResolversWin32(resolvers);
return updateResolversWin32(entry.InterfaceGuid, resolvers);
}

bool DnsUtilsWindows::updateResolversWin32(
const QList<QHostAddress>& resolvers) {
GUID guid;
NET_LUID luid;
luid.Value = m_luid;
if (ConvertInterfaceLuidToGuid(&luid, &guid) != NO_ERROR) {
logger.error() << "Failed to resolve GUID";
return false;
}

GUID guid, const QList<QHostAddress>& resolvers) {
QStringList v4resolvers;
QStringList v6resolvers;
for (const QHostAddress& addr : resolvers) {
Expand Down Expand Up @@ -113,16 +113,8 @@ constexpr const char* netshAddTemplate =
"interface %1 add dnsservers name=%2 address=%3 validate=no\r\n";

bool DnsUtilsWindows::updateResolversNetsh(
const QList<QHostAddress>& resolvers) {
int ifindex, const QList<QHostAddress>& resolvers) {
QProcess netsh;
NET_LUID luid;
NET_IFINDEX ifindex;
luid.Value = m_luid;
if (ConvertInterfaceLuidToIndex(&luid, &ifindex) != NO_ERROR) {
logger.error() << "Failed to resolve GUID";
return false;
}

netsh.setProgram("netsh");
netsh.start();
if (!netsh.waitForStarted(WINDOWS_NETSH_TIMEOUT_MSEC)) {
Expand Down Expand Up @@ -166,12 +158,26 @@ bool DnsUtilsWindows::updateResolversNetsh(

bool DnsUtilsWindows::restoreResolvers() {
if (m_luid == 0) {
// If the DNS hasn't been configured, there is nothing to restore.
return true;
}

MIB_IF_ROW2 entry;
DWORD error;
entry.InterfaceLuid.Value = m_luid;
error = GetIfEntry2(&entry);
if (error == ERROR_FILE_NOT_FOUND) {
// If the interface no longer exists, there is nothing to restore.
return true;
}
if (error != NO_ERROR) {
logger.error() << "Failed to resolve interface entry:" << error;
return false;
}

QList<QHostAddress> empty;
if (m_setInterfaceDnsSettingsProcAddr == nullptr) {
return updateResolversNetsh(empty);
return updateResolversNetsh(entry.InterfaceIndex, empty);
}
return updateResolversWin32(empty);
return updateResolversWin32(entry.InterfaceGuid, empty);
}
4 changes: 2 additions & 2 deletions src/platforms/windows/daemon/dnsutilswindows.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class DnsUtilsWindows final : public DnsUtils {
quint64 m_luid = 0;
DWORD (*m_setInterfaceDnsSettingsProcAddr)(GUID, const void*) = nullptr;

bool updateResolversWin32(const QList<QHostAddress>& resolvers);
bool updateResolversNetsh(const QList<QHostAddress>& resolvers);
bool updateResolversWin32(GUID, const QList<QHostAddress>& resolvers);
bool updateResolversNetsh(int ifindex, const QList<QHostAddress>& resolvers);
};

#endif // DNSUTILSWINDOWS_H
1 change: 0 additions & 1 deletion src/platforms/windows/daemon/windowsdaemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class WindowsDaemon final : public Daemon {
protected:
bool run(Op op, const InterfaceConfig& config) override;
WireguardUtils* wgutils() const override { return m_wgutils; }
bool supportDnsUtils() const override { return true; }
DnsUtils* dnsutils() override { return m_dnsutils; }

private:
Expand Down
10 changes: 10 additions & 0 deletions src/platforms/windows/daemon/windowstunnelservice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,22 @@ static bool waitForServiceStatus(SC_HANDLE service, DWORD expectedStatus);

WindowsTunnelService::WindowsTunnelService(QObject* parent) : QObject(parent) {
MZ_COUNT_CTOR(WindowsTunnelService);
logger.debug() << "WindowsTunnelService created.";

m_scm = OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
if (m_scm == nullptr) {
WindowsUtils::windowsLog("Failed to open SCManager");
}

// Is the service already running? Terminate it.
SC_HANDLE service =
OpenService((SC_HANDLE)m_scm, TUNNEL_SERVICE_NAME, SERVICE_ALL_ACCESS);
if (service != nullptr) {
logger.info() << "Tunnel already exists. Terminating it.";
stopAndDeleteTunnelService(service);
CloseServiceHandle(service);
}

connect(&m_timer, &QTimer::timeout, this, &WindowsTunnelService::timeout);
}

Expand Down
2 changes: 0 additions & 2 deletions src/platforms/windows/windowscommons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
#include "logger.h"
#include "platforms/windows/windowsutils.h"

#define TUNNEL_SERVICE_NAME L"WireGuardTunnel$mozvpn"

constexpr const char* VPN_NAME = "MozillaVPN";
constexpr const char* WIREGUARD_DIR = "WireGuard";
constexpr const char* DATA_DIR = "Data";
Expand Down
Loading