mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-20 02:00:55 +07:00
feat: seamless WG switch on Windows for shared client IPs
This commit is contained in:
@@ -360,9 +360,9 @@ void VpnTrafficGuard::applyPolicy(Tunnel* tunnel)
|
||||
const QString peer = tunnel->remoteAddress();
|
||||
|
||||
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
if (!peer.isEmpty()) iface->addExclusionRoute(peer);
|
||||
if (!peer.isEmpty()) iface->addExclusionRoute(ifname, peer);
|
||||
for (const QString& addr : excluded) {
|
||||
iface->addExclusionRoute(addr);
|
||||
iface->addExclusionRoute(ifname, addr);
|
||||
}
|
||||
for (const QString& prefix : prefixes) {
|
||||
iface->addAllowedIp(ifname, prefix);
|
||||
@@ -390,9 +390,9 @@ void VpnTrafficGuard::revokePolicy(Tunnel* tunnel)
|
||||
iface->delAllowedIp(ifname, prefix);
|
||||
}
|
||||
for (const QString& addr : excluded) {
|
||||
iface->delExclusionRoute(addr);
|
||||
iface->delExclusionRoute(ifname, addr);
|
||||
}
|
||||
if (!peer.isEmpty()) iface->delExclusionRoute(peer);
|
||||
if (!peer.isEmpty()) iface->delExclusionRoute(ifname, peer);
|
||||
});
|
||||
#else
|
||||
Q_UNUSED(tunnel)
|
||||
|
||||
@@ -85,7 +85,9 @@ bool Daemon::activate(const QString& ifname, const InterfaceConfig& config) {
|
||||
|
||||
// Bring up the wireguard interface if not already done.
|
||||
if (!wg->interfaceExists()) {
|
||||
if (!wg->addInterface(config)) {
|
||||
InterfaceConfig bringupConfig = config;
|
||||
bringupConfig.m_deferAddressSetup = (m_primaryIfname != ifname);
|
||||
if (!wg->addInterface(bringupConfig)) {
|
||||
logger.error() << "Interface creation failed.";
|
||||
return false;
|
||||
}
|
||||
@@ -126,6 +128,14 @@ bool Daemon::setPrimary(const QString& ifname, const InterfaceConfig& config) {
|
||||
const QString priorPrimary = m_primaryIfname;
|
||||
m_primaryIfname = ifname;
|
||||
|
||||
if (!priorPrimary.isEmpty() && priorPrimary != ifname) {
|
||||
if (WireguardUtils* oldWg = m_tunnels.value(priorPrimary)) {
|
||||
const InterfaceConfig& oldConfig = m_connections.value(priorPrimary).m_config;
|
||||
oldWg->removeDeviceAddresses(oldConfig.m_deviceIpv4Address, oldConfig.m_deviceIpv6Address);
|
||||
}
|
||||
}
|
||||
wg->applyDeviceAddresses(config.m_deviceIpv4Address, config.m_deviceIpv6Address);
|
||||
|
||||
auto failure_guard = qScopeGuard([this, ifname, priorPrimary] {
|
||||
deactivateTunnel(ifname);
|
||||
m_primaryIfname = priorPrimary;
|
||||
@@ -190,13 +200,14 @@ bool Daemon::parseStringList(const QJsonObject& obj, const QString& name,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Daemon::addExclusionRoute(const QString &addr) {
|
||||
bool Daemon::addExclusionRoute(const QString &ifname, const QString &addr) {
|
||||
IPAddress prefix(addr);
|
||||
if (m_excludedAddrSet.contains(prefix)) {
|
||||
m_excludedAddrSet[prefix]++;
|
||||
return true;
|
||||
}
|
||||
WireguardUtils* wg = primaryWgutils();
|
||||
WireguardUtils* wg = wgutilsFor(ifname);
|
||||
if (!wg) wg = primaryWgutils();
|
||||
if (!wg || !wg->addExclusionRoute(prefix)) {
|
||||
return false;
|
||||
}
|
||||
@@ -204,7 +215,7 @@ bool Daemon::addExclusionRoute(const QString &addr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Daemon::delExclusionRoute(const QString &addr) {
|
||||
bool Daemon::delExclusionRoute(const QString &ifname, const QString &addr) {
|
||||
IPAddress prefix(addr);
|
||||
if (!m_excludedAddrSet.contains(prefix)) {
|
||||
return false;
|
||||
@@ -214,7 +225,8 @@ bool Daemon::delExclusionRoute(const QString &addr) {
|
||||
return true;
|
||||
}
|
||||
m_excludedAddrSet.remove(prefix);
|
||||
WireguardUtils* wg = primaryWgutils();
|
||||
WireguardUtils* wg = wgutilsFor(ifname);
|
||||
if (!wg) wg = primaryWgutils();
|
||||
return wg && wg->deleteExclusionRoute(prefix);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ class Daemon : public QObject {
|
||||
virtual bool deactivate(bool emitSignals = true);
|
||||
virtual QJsonObject getStatus();
|
||||
|
||||
bool addExclusionRoute(const QString &addr);
|
||||
bool delExclusionRoute(const QString &addr);
|
||||
bool addExclusionRoute(const QString &ifname, const QString &addr);
|
||||
bool delExclusionRoute(const QString &ifname, const QString &addr);
|
||||
bool addAllowedIp(const QString &ifname, const QString &prefix);
|
||||
bool delAllowedIp(const QString &ifname, const QString &prefix);
|
||||
bool setTunnelResolvers(const QString &ifname, const QStringList &resolvers);
|
||||
|
||||
@@ -60,6 +60,7 @@ class InterfaceConfig {
|
||||
QString m_transportPacketMagicHeader;
|
||||
QMap<QString, QString> m_specialJunk;
|
||||
QString m_ifname;
|
||||
bool m_deferAddressSetup = false;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
QString toWgConf(
|
||||
|
||||
@@ -37,6 +37,9 @@ class WireguardUtils : public QObject {
|
||||
virtual bool addInterface(const InterfaceConfig& config) = 0;
|
||||
virtual bool deleteInterface() = 0;
|
||||
|
||||
virtual bool applyDeviceAddresses(const QString& ipv4Address, const QString& ipv6Address) { return true; }
|
||||
virtual bool removeDeviceAddresses(const QString& ipv4Address, const QString& ipv6Address) { return true; }
|
||||
|
||||
virtual bool updatePeer(const InterfaceConfig& config) = 0;
|
||||
virtual bool deletePeer(const InterfaceConfig& config) = 0;
|
||||
virtual QList<PeerStatus> getPeerStatus() = 0;
|
||||
|
||||
@@ -58,9 +58,12 @@ static int prefixcmp(const void* a, const void* b, size_t bits) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
QSet<quint64> WindowsRouteMonitor::s_vpnLuids;
|
||||
|
||||
WindowsRouteMonitor::WindowsRouteMonitor(quint64 luid, QObject* parent)
|
||||
: QObject(parent), m_luid(luid) {
|
||||
MZ_COUNT_CTOR(WindowsRouteMonitor);
|
||||
s_vpnLuids.insert(luid);
|
||||
logger.debug() << "WindowsRouteMonitor created.";
|
||||
|
||||
NotifyRouteChange2(AF_INET, routeChangeCallback, this, FALSE, &m_routeHandle);
|
||||
@@ -69,8 +72,8 @@ WindowsRouteMonitor::WindowsRouteMonitor(quint64 luid, QObject* parent)
|
||||
WindowsRouteMonitor::~WindowsRouteMonitor() {
|
||||
MZ_COUNT_DTOR(WindowsRouteMonitor);
|
||||
CancelMibChangeNotify2(m_routeHandle);
|
||||
s_vpnLuids.remove(m_luid);
|
||||
|
||||
flushRouteTable(m_exclusionRoutes);
|
||||
flushRouteTable(m_clonedRoutes);
|
||||
logger.debug() << "WindowsRouteMonitor destroyed.";
|
||||
}
|
||||
@@ -95,7 +98,8 @@ void WindowsRouteMonitor::updateInterfaceMetrics(int family) {
|
||||
// Rebuild the list of interfaces that are valid for routing.
|
||||
for (ULONG i = 0; i < table->NumEntries; i++) {
|
||||
MIB_IPINTERFACE_ROW* row = &table->Table[i];
|
||||
if (row->InterfaceLuid.Value == m_luid) {
|
||||
// Skip any VPN wintun (own or sibling) so exclusion routes never pick one.
|
||||
if (s_vpnLuids.contains(row->InterfaceLuid.Value)) {
|
||||
continue;
|
||||
}
|
||||
if (!row->Connected) {
|
||||
@@ -126,8 +130,8 @@ void WindowsRouteMonitor::updateExclusionRoute(MIB_IPFORWARD_ROW2* data,
|
||||
nexthop.si_family = data->DestinationPrefix.Prefix.si_family;
|
||||
for (ULONG i = 0; i < table->NumEntries; i++) {
|
||||
MIB_IPFORWARD_ROW2* row = &table->Table[i];
|
||||
// Ignore routes into the VPN interface.
|
||||
if (row->InterfaceLuid.Value == m_luid) {
|
||||
// Skip any VPN wintun (own or sibling).
|
||||
if (s_vpnLuids.contains(row->InterfaceLuid.Value)) {
|
||||
continue;
|
||||
}
|
||||
if (row->DestinationPrefix.PrefixLength < bestMatch) {
|
||||
@@ -239,14 +243,16 @@ QHostAddress WindowsRouteMonitor::prefixToAddress(
|
||||
}
|
||||
}
|
||||
|
||||
bool WindowsRouteMonitor::isRouteExcluded(const IP_ADDRESS_PREFIX* dest) const {
|
||||
auto i = m_exclusionRoutes.constBegin();
|
||||
while (i != m_exclusionRoutes.constEnd()) {
|
||||
const MIB_IPFORWARD_ROW2* row = i.value();
|
||||
bool WindowsRouteMonitor::isRouteExcluded(void* ptable,
|
||||
const IP_ADDRESS_PREFIX* dest) const {
|
||||
PMIB_IPFORWARD_TABLE2 table = reinterpret_cast<PMIB_IPFORWARD_TABLE2>(ptable);
|
||||
for (ULONG i = 0; i < table->NumEntries; i++) {
|
||||
const MIB_IPFORWARD_ROW2* row = &table->Table[i];
|
||||
if (row->Protocol != MIB_IPPROTO_NETMGMT) continue;
|
||||
if (row->Metric != EXCLUSION_ROUTE_METRIC) continue;
|
||||
if (routeContainsDest(&row->DestinationPrefix, dest)) {
|
||||
return true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -272,8 +278,8 @@ void WindowsRouteMonitor::updateCapturedRoutes(int family, void* ptable) {
|
||||
|
||||
for (ULONG i = 0; i < table->NumEntries; i++) {
|
||||
MIB_IPFORWARD_ROW2* row = &table->Table[i];
|
||||
// Ignore routes into the VPN interface.
|
||||
if (row->InterfaceLuid.Value == m_luid) {
|
||||
// Skip any VPN wintun (own or sibling).
|
||||
if (s_vpnLuids.contains(row->InterfaceLuid.Value)) {
|
||||
continue;
|
||||
}
|
||||
// Ignore the default route
|
||||
@@ -286,7 +292,7 @@ void WindowsRouteMonitor::updateCapturedRoutes(int family, void* ptable) {
|
||||
continue;
|
||||
}
|
||||
// Ignore routes which should be excluded.
|
||||
if (isRouteExcluded(&row->DestinationPrefix)) {
|
||||
if (isRouteExcluded(table, &row->DestinationPrefix)) {
|
||||
continue;
|
||||
}
|
||||
QHostAddress destination = prefixToAddress(&row->DestinationPrefix);
|
||||
@@ -375,11 +381,6 @@ bool WindowsRouteMonitor::addExclusionRoute(const IPAddress& prefix) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_exclusionRoutes.contains(prefix)) {
|
||||
logger.warning() << "Exclusion route already exists";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate and initialize the MIB routing table row.
|
||||
MIB_IPFORWARD_ROW2* data = new MIB_IPFORWARD_ROW2;
|
||||
InitializeIpForwardEntry(data);
|
||||
@@ -427,8 +428,8 @@ bool WindowsRouteMonitor::addExclusionRoute(const IPAddress& prefix) {
|
||||
updateCapturedRoutes(family, table);
|
||||
updateExclusionRoute(data, table);
|
||||
FreeMibTable(table);
|
||||
|
||||
m_exclusionRoutes[prefix] = data;
|
||||
delete data;
|
||||
m_ownedExclusionRoutes.insert(prefix);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -436,23 +437,39 @@ bool WindowsRouteMonitor::deleteExclusionRoute(const IPAddress& prefix) {
|
||||
logger.debug() << "Deleting exclusion route for"
|
||||
<< prefix.address().toString();
|
||||
|
||||
MIB_IPFORWARD_ROW2* data = m_exclusionRoutes.take(prefix);
|
||||
if (data == nullptr) {
|
||||
return true;
|
||||
m_ownedExclusionRoutes.remove(prefix);
|
||||
|
||||
PMIB_IPFORWARD_TABLE2 table;
|
||||
DWORD result = GetIpForwardTable2(AF_UNSPEC, &table);
|
||||
if (result != NO_ERROR) {
|
||||
logger.error() << "Failed to fetch routing table:" << result;
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD result = DeleteIpForwardEntry2(data);
|
||||
if ((result != ERROR_NOT_FOUND) && (result != NO_ERROR)) {
|
||||
logger.error() << "Failed to delete route to"
|
||||
<< prefix.toString()
|
||||
<< "result:" << result;
|
||||
const bool isV4 = prefix.address().protocol() == QAbstractSocket::IPv4Protocol;
|
||||
const ADDRESS_FAMILY addrFamily =
|
||||
isV4 ? static_cast<ADDRESS_FAMILY>(AF_INET)
|
||||
: static_cast<ADDRESS_FAMILY>(AF_INET6);
|
||||
bool deleted = false;
|
||||
for (ULONG i = 0; i < table->NumEntries; i++) {
|
||||
MIB_IPFORWARD_ROW2* row = &table->Table[i];
|
||||
if (row->Protocol != MIB_IPPROTO_NETMGMT) continue;
|
||||
if (row->Metric != EXCLUSION_ROUTE_METRIC) continue;
|
||||
if (row->DestinationPrefix.Prefix.si_family != addrFamily) continue;
|
||||
if (row->DestinationPrefix.PrefixLength != prefix.prefixLength()) continue;
|
||||
if (prefixToAddress(&row->DestinationPrefix) != prefix.address()) continue;
|
||||
DWORD r = DeleteIpForwardEntry2(row);
|
||||
if (r == NO_ERROR || r == ERROR_NOT_FOUND) {
|
||||
deleted = true;
|
||||
} else {
|
||||
logger.error() << "Failed to delete route to" << prefix.toString()
|
||||
<< "result:" << r;
|
||||
}
|
||||
|
||||
// Captured routes might have changed.
|
||||
updateCapturedRoutes(data->DestinationPrefix.Prefix.si_family);
|
||||
|
||||
delete data;
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
FreeMibTable(table);
|
||||
updateCapturedRoutes(addrFamily);
|
||||
return deleted;
|
||||
}
|
||||
|
||||
void WindowsRouteMonitor::flushRouteTable(
|
||||
@@ -492,8 +509,24 @@ void WindowsRouteMonitor::routeChanged() {
|
||||
|
||||
updateInterfaceMetrics(AF_UNSPEC);
|
||||
updateCapturedRoutes(AF_UNSPEC, table);
|
||||
for (MIB_IPFORWARD_ROW2* data : m_exclusionRoutes) {
|
||||
updateExclusionRoute(data, table);
|
||||
|
||||
for (const IPAddress& prefix : m_ownedExclusionRoutes) {
|
||||
const bool isV4 =
|
||||
prefix.address().protocol() == QAbstractSocket::IPv4Protocol;
|
||||
const ADDRESS_FAMILY addrFamily =
|
||||
isV4 ? static_cast<ADDRESS_FAMILY>(AF_INET)
|
||||
: static_cast<ADDRESS_FAMILY>(AF_INET6);
|
||||
for (ULONG i = 0; i < table->NumEntries; i++) {
|
||||
MIB_IPFORWARD_ROW2* row = &table->Table[i];
|
||||
if (row->Protocol != MIB_IPPROTO_NETMGMT) continue;
|
||||
if (row->Metric != EXCLUSION_ROUTE_METRIC) continue;
|
||||
if (row->DestinationPrefix.Prefix.si_family != addrFamily) continue;
|
||||
if (row->DestinationPrefix.PrefixLength != prefix.prefixLength()) continue;
|
||||
if (prefixToAddress(&row->DestinationPrefix) != prefix.address()) continue;
|
||||
MIB_IPFORWARD_ROW2 copy = *row;
|
||||
updateExclusionRoute(©, table);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FreeMibTable(table);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <QHash>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
|
||||
#include "ipaddress.h"
|
||||
|
||||
@@ -28,7 +29,6 @@ class WindowsRouteMonitor final : public QObject {
|
||||
|
||||
bool addExclusionRoute(const IPAddress& prefix);
|
||||
bool deleteExclusionRoute(const IPAddress& prefix);
|
||||
void flushExclusionRoutes() { return flushRouteTable(m_exclusionRoutes); };
|
||||
|
||||
quint64 getLuid() const { return m_luid; }
|
||||
|
||||
@@ -36,7 +36,7 @@ class WindowsRouteMonitor final : public QObject {
|
||||
void routeChanged();
|
||||
|
||||
private:
|
||||
bool isRouteExcluded(const IP_ADDRESS_PREFIX* dest) const;
|
||||
bool isRouteExcluded(void* table, const IP_ADDRESS_PREFIX* dest) const;
|
||||
static bool routeContainsDest(const IP_ADDRESS_PREFIX* route,
|
||||
const IP_ADDRESS_PREFIX* dest);
|
||||
static QHostAddress prefixToAddress(const IP_ADDRESS_PREFIX* dest);
|
||||
@@ -47,7 +47,7 @@ class WindowsRouteMonitor final : public QObject {
|
||||
void updateCapturedRoutes(int family);
|
||||
void updateCapturedRoutes(int family, void* table);
|
||||
|
||||
QHash<IPAddress, MIB_IPFORWARD_ROW2*> m_exclusionRoutes;
|
||||
QSet<IPAddress> m_ownedExclusionRoutes;
|
||||
QMap<quint64, ULONG> m_interfaceMetricsIpv4;
|
||||
QMap<quint64, ULONG> m_interfaceMetricsIpv6;
|
||||
|
||||
@@ -57,6 +57,8 @@ class WindowsRouteMonitor final : public QObject {
|
||||
|
||||
const quint64 m_luid = 0;
|
||||
HANDLE m_routeHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
static QSet<quint64> s_vpnLuids;
|
||||
};
|
||||
|
||||
#endif /* WINDOWSROUTEMONITOR_H */
|
||||
|
||||
@@ -107,12 +107,21 @@ bool WireguardUtilsWindows::addInterface(const InterfaceConfig& config) {
|
||||
configString.truncate(peerStart);
|
||||
}
|
||||
|
||||
qsizetype dnsStart = configString.indexOf("DNS = ");
|
||||
if (dnsStart >= 0) {
|
||||
qsizetype dnsEnd = configString.indexOf('\n', dnsStart);
|
||||
if (dnsEnd >= 0) {
|
||||
configString.remove(dnsStart, dnsEnd - dnsStart + 1);
|
||||
}
|
||||
auto stripLine = [&](const QString& key) {
|
||||
qsizetype start = configString.startsWith(key + " = ")
|
||||
? 0
|
||||
: configString.indexOf("\n" + key + " = ");
|
||||
if (start < 0) return;
|
||||
if (start != 0) start += 1;
|
||||
qsizetype end = configString.indexOf('\n', start);
|
||||
if (end < 0) return;
|
||||
configString.remove(start, end - start + 1);
|
||||
};
|
||||
|
||||
stripLine("DNS");
|
||||
if (config.m_deferAddressSetup) {
|
||||
// Wintun rejects duplicate IPv4; daemon will assign at swap time.
|
||||
stripLine("Address");
|
||||
}
|
||||
|
||||
m_ifname = config.m_ifname.isEmpty() ? s_defaultInterfaceName() : config.m_ifname;
|
||||
@@ -143,6 +152,60 @@ bool WireguardUtilsWindows::deleteInterface() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WireguardUtilsWindows::applyDeviceAddresses(const QString& ipv4Address,
|
||||
const QString& ipv6Address) {
|
||||
auto applyOne = [&](const QString& addr, int family, uint8_t prefix) -> bool {
|
||||
if (addr.isEmpty()) return true;
|
||||
const QByteArray ip = addr.section('/', 0, 0).toUtf8();
|
||||
MIB_UNICASTIPADDRESS_ROW row;
|
||||
InitializeUnicastIpAddressEntry(&row);
|
||||
row.InterfaceLuid.Value = m_luid;
|
||||
row.Address.si_family = static_cast<ADDRESS_FAMILY>(family);
|
||||
row.OnLinkPrefixLength = prefix;
|
||||
row.DadState = IpDadStatePreferred;
|
||||
void* dst = (family == AF_INET)
|
||||
? static_cast<void*>(&row.Address.Ipv4.sin_addr)
|
||||
: static_cast<void*>(&row.Address.Ipv6.sin6_addr);
|
||||
if (InetPtonA(family, ip.constData(), dst) != 1) {
|
||||
logger.error() << "applyDeviceAddresses: cannot parse" << addr;
|
||||
return false;
|
||||
}
|
||||
DWORD r = CreateUnicastIpAddressEntry(&row);
|
||||
logger.debug() << "Apply" << addr << "to" << m_ifname << "result:" << r;
|
||||
return r == NO_ERROR || r == ERROR_OBJECT_ALREADY_EXISTS;
|
||||
};
|
||||
|
||||
if (!applyOne(ipv4Address, AF_INET, 32)) return false;
|
||||
if (!applyOne(ipv6Address, AF_INET6, 128)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WireguardUtilsWindows::removeDeviceAddresses(const QString& ipv4Address,
|
||||
const QString& ipv6Address) {
|
||||
auto removeOne = [&](const QString& addr, int family) -> bool {
|
||||
if (addr.isEmpty()) return true;
|
||||
const QByteArray ip = addr.section('/', 0, 0).toUtf8();
|
||||
MIB_UNICASTIPADDRESS_ROW row;
|
||||
InitializeUnicastIpAddressEntry(&row);
|
||||
row.InterfaceLuid.Value = m_luid;
|
||||
row.Address.si_family = static_cast<ADDRESS_FAMILY>(family);
|
||||
void* dst = (family == AF_INET)
|
||||
? static_cast<void*>(&row.Address.Ipv4.sin_addr)
|
||||
: static_cast<void*>(&row.Address.Ipv6.sin6_addr);
|
||||
if (InetPtonA(family, ip.constData(), dst) != 1) {
|
||||
logger.error() << "removeDeviceAddresses: cannot parse" << addr;
|
||||
return false;
|
||||
}
|
||||
DWORD r = DeleteUnicastIpAddressEntry(&row);
|
||||
logger.debug() << "Remove" << addr << "from" << m_ifname << "result:" << r;
|
||||
return r == NO_ERROR || r == ERROR_NOT_FOUND;
|
||||
};
|
||||
|
||||
bool ok = removeOne(ipv4Address, AF_INET);
|
||||
ok &= removeOne(ipv6Address, AF_INET6);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool WireguardUtilsWindows::updatePeer(const InterfaceConfig& config) {
|
||||
QByteArray publicKey =
|
||||
QByteArray::fromBase64(qPrintable(config.m_serverPublicKey));
|
||||
|
||||
@@ -32,6 +32,9 @@ class WireguardUtilsWindows final : public WireguardUtils {
|
||||
bool addInterface(const InterfaceConfig& config) override;
|
||||
bool deleteInterface() override;
|
||||
|
||||
bool applyDeviceAddresses(const QString& ipv4Address, const QString& ipv6Address) override;
|
||||
bool removeDeviceAddresses(const QString& ipv4Address, const QString& ipv6Address) override;
|
||||
|
||||
bool updatePeer(const InterfaceConfig& config) override;
|
||||
bool deletePeer(const InterfaceConfig& config) override;
|
||||
QList<PeerStatus> getPeerStatus() override;
|
||||
|
||||
@@ -169,22 +169,10 @@ void VpnConnection::connectToVpn(const QString &serverId, DockerContainer contai
|
||||
const bool isWg = VpnProtocol::isWireGuardBased(container);
|
||||
const QString preAllocatedIfname = isWg ? allocateIfname() : QString();
|
||||
|
||||
bool seamlessSwitch = m_active
|
||||
// Seamless WG -> WG switch path: already connected via Tunnel, new container is also WG.
|
||||
if (m_active
|
||||
&& m_connectionState == Vpn::ConnectionState::Connected
|
||||
&& isWg;
|
||||
#ifdef Q_OS_WIN
|
||||
if (seamlessSwitch) {
|
||||
auto clientIpFor = [](const QJsonObject& cfg) {
|
||||
const QString proto = cfg.value("protocol").toString();
|
||||
return cfg.value(proto + "_config_data").toObject().value(configKey::clientIp).toString();
|
||||
};
|
||||
if (clientIpFor(vpnConfiguration) == clientIpFor(m_active->config())) {
|
||||
seamlessSwitch = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (seamlessSwitch) {
|
||||
&& isWg) {
|
||||
if (!m_trafficGuard->allowEndpoint(resolvedRemote, preAllocatedIfname)) {
|
||||
releaseIfname(preAllocatedIfname);
|
||||
setConnectionState(Vpn::ConnectionState::Error);
|
||||
|
||||
@@ -12,8 +12,8 @@ class IpcInterface
|
||||
SLOT( int routeAddList(const QString &gw, const QStringList &ips) );
|
||||
SLOT( bool clearSavedRoutes() );
|
||||
SLOT( bool routeDeleteList(const QString &gw, const QStringList &ip) );
|
||||
SLOT( bool addExclusionRoute(const QString &addr) );
|
||||
SLOT( bool delExclusionRoute(const QString &addr) );
|
||||
SLOT( bool addExclusionRoute(const QString &ifname, const QString &addr) );
|
||||
SLOT( bool delExclusionRoute(const QString &ifname, const QString &addr) );
|
||||
SLOT( bool addAllowedIp(const QString &ifname, const QString &prefix) );
|
||||
SLOT( bool delAllowedIp(const QString &ifname, const QString &prefix) );
|
||||
SLOT( bool setTunnelResolvers(const QString &ifname, const QStringList &resolvers) );
|
||||
|
||||
+4
-4
@@ -93,14 +93,14 @@ bool IpcServer::routeDeleteList(const QString &gw, const QStringList &ips)
|
||||
return Router::routeDeleteList(gw, ips);
|
||||
}
|
||||
|
||||
bool IpcServer::addExclusionRoute(const QString &addr)
|
||||
bool IpcServer::addExclusionRoute(const QString &ifname, const QString &addr)
|
||||
{
|
||||
return Daemon::instance() && Daemon::instance()->addExclusionRoute(addr);
|
||||
return Daemon::instance() && Daemon::instance()->addExclusionRoute(ifname, addr);
|
||||
}
|
||||
|
||||
bool IpcServer::delExclusionRoute(const QString &addr)
|
||||
bool IpcServer::delExclusionRoute(const QString &ifname, const QString &addr)
|
||||
{
|
||||
return Daemon::instance() && Daemon::instance()->delExclusionRoute(addr);
|
||||
return Daemon::instance() && Daemon::instance()->delExclusionRoute(ifname, addr);
|
||||
}
|
||||
|
||||
bool IpcServer::addAllowedIp(const QString &ifname, const QString &prefix)
|
||||
|
||||
+2
-2
@@ -23,8 +23,8 @@ public:
|
||||
virtual int routeAddList(const QString &gw, const QStringList &ips) override;
|
||||
virtual bool clearSavedRoutes() override;
|
||||
virtual bool routeDeleteList(const QString &gw, const QStringList &ips) override;
|
||||
virtual bool addExclusionRoute(const QString &addr) override;
|
||||
virtual bool delExclusionRoute(const QString &addr) override;
|
||||
virtual bool addExclusionRoute(const QString &ifname, const QString &addr) override;
|
||||
virtual bool delExclusionRoute(const QString &ifname, const QString &addr) override;
|
||||
virtual bool addAllowedIp(const QString &ifname, const QString &prefix) override;
|
||||
virtual bool delAllowedIp(const QString &ifname, const QString &prefix) override;
|
||||
virtual bool setTunnelResolvers(const QString &ifname, const QStringList &resolvers) override;
|
||||
|
||||
Reference in New Issue
Block a user