mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
refactor: TrafficGuard owns adapter IP swap for WG/AWG and Xray
This commit is contained in:
@@ -457,20 +457,11 @@ void VpnTrafficGuard::commit(Tunnel* tunnel)
|
|||||||
{
|
{
|
||||||
if (!tunnel) return;
|
if (!tunnel) return;
|
||||||
|
|
||||||
#if defined(AMNEZIA_DESKTOP) && defined(Q_OS_WIN)
|
#ifdef Q_OS_WIN
|
||||||
if (VpnProtocol::isXrayBased(tunnel->container())) {
|
const QString ipv4 = tunnel->config().value(QStringLiteral("deviceIpv4Address")).toString();
|
||||||
const QJsonObject &cfg = tunnel->config();
|
const QString ipv6 = tunnel->config().value(QStringLiteral("deviceIpv6Address")).toString();
|
||||||
const QString ipv4 = cfg.value(QStringLiteral("deviceIpv4Address")).toString();
|
if (!ipv4.isEmpty() || !ipv6.isEmpty()) {
|
||||||
const QString ipv6 = cfg.value(QStringLiteral("deviceIpv6Address")).toString();
|
|
||||||
const QString handover = tunnel->handoverIfname();
|
|
||||||
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||||
if (!handover.isEmpty() && handover != tunnel->ifname()) {
|
|
||||||
auto rm = iface->removeAdapterAddress(handover, ipv4, ipv6);
|
|
||||||
if (!rm.waitForFinished(2000) || !rm.returnValue()) {
|
|
||||||
qWarning() << "VpnTrafficGuard::commit: removeAdapterAddress failed for"
|
|
||||||
<< handover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto ap = iface->applyAdapterAddress(tunnel->ifname(), ipv4, ipv6);
|
auto ap = iface->applyAdapterAddress(tunnel->ifname(), ipv4, ipv6);
|
||||||
if (!ap.waitForFinished(15000) || !ap.returnValue()) {
|
if (!ap.waitForFinished(15000) || !ap.returnValue()) {
|
||||||
qWarning() << "VpnTrafficGuard::commit: applyAdapterAddress failed for"
|
qWarning() << "VpnTrafficGuard::commit: applyAdapterAddress failed for"
|
||||||
@@ -510,6 +501,22 @@ void VpnTrafficGuard::swap(Tunnel* from, Tunnel* to)
|
|||||||
to->setHandoverIfname(from->ifname());
|
to->setHandoverIfname(from->ifname());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
if (from) {
|
||||||
|
const QString fromIpv4 = from->config().value(QStringLiteral("deviceIpv4Address")).toString();
|
||||||
|
const QString fromIpv6 = from->config().value(QStringLiteral("deviceIpv6Address")).toString();
|
||||||
|
if (!fromIpv4.isEmpty() || !fromIpv6.isEmpty()) {
|
||||||
|
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||||
|
auto rm = iface->removeAdapterAddress(from->ifname(), fromIpv4, fromIpv6);
|
||||||
|
if (!rm.waitForFinished(2000) || !rm.returnValue()) {
|
||||||
|
qWarning() << "VpnTrafficGuard::swap: removeAdapterAddress failed for"
|
||||||
|
<< from->ifname();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
QTimer guard;
|
QTimer guard;
|
||||||
guard.setSingleShot(true);
|
guard.setSingleShot(true);
|
||||||
|
|||||||
@@ -128,14 +128,6 @@ bool Daemon::setPrimary(const QString& ifname, const InterfaceConfig& config) {
|
|||||||
const QString priorPrimary = m_primaryIfname;
|
const QString priorPrimary = m_primaryIfname;
|
||||||
m_primaryIfname = ifname;
|
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] {
|
auto failure_guard = qScopeGuard([this, ifname, priorPrimary] {
|
||||||
deactivateTunnel(ifname);
|
deactivateTunnel(ifname);
|
||||||
m_primaryIfname = priorPrimary;
|
m_primaryIfname = priorPrimary;
|
||||||
|
|||||||
@@ -37,9 +37,6 @@ class WireguardUtils : public QObject {
|
|||||||
virtual bool addInterface(const InterfaceConfig& config) = 0;
|
virtual bool addInterface(const InterfaceConfig& config) = 0;
|
||||||
virtual bool deleteInterface() = 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 updatePeer(const InterfaceConfig& config) = 0;
|
||||||
virtual bool deletePeer(const InterfaceConfig& config) = 0;
|
virtual bool deletePeer(const InterfaceConfig& config) = 0;
|
||||||
virtual QList<PeerStatus> getPeerStatus() = 0;
|
virtual QList<PeerStatus> getPeerStatus() = 0;
|
||||||
|
|||||||
@@ -152,60 +152,6 @@ bool WireguardUtilsWindows::deleteInterface() {
|
|||||||
return true;
|
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) {
|
bool WireguardUtilsWindows::updatePeer(const InterfaceConfig& config) {
|
||||||
QByteArray publicKey =
|
QByteArray publicKey =
|
||||||
QByteArray::fromBase64(qPrintable(config.m_serverPublicKey));
|
QByteArray::fromBase64(qPrintable(config.m_serverPublicKey));
|
||||||
|
|||||||
@@ -32,9 +32,6 @@ class WireguardUtilsWindows final : public WireguardUtils {
|
|||||||
bool addInterface(const InterfaceConfig& config) override;
|
bool addInterface(const InterfaceConfig& config) override;
|
||||||
bool deleteInterface() 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 updatePeer(const InterfaceConfig& config) override;
|
||||||
bool deletePeer(const InterfaceConfig& config) override;
|
bool deletePeer(const InterfaceConfig& config) override;
|
||||||
QList<PeerStatus> getPeerStatus() override;
|
QList<PeerStatus> getPeerStatus() override;
|
||||||
|
|||||||
@@ -224,6 +224,13 @@ void VpnConnection::connectToVpn(const QString &serverId, DockerContainer contai
|
|||||||
if (isXray) {
|
if (isXray) {
|
||||||
config.insert("tunName", preAllocatedIfname);
|
config.insert("tunName", preAllocatedIfname);
|
||||||
config.insert("deviceIpv4Address", amnezia::protocols::xray::defaultLocalAddr);
|
config.insert("deviceIpv4Address", amnezia::protocols::xray::defaultLocalAddr);
|
||||||
|
} else if (isWg) {
|
||||||
|
const QString protoName = config.value("protocol").toString();
|
||||||
|
const QJsonObject wgConfig = config.value(protoName + "_config_data").toObject();
|
||||||
|
const QString clientIp = wgConfig.value(amnezia::configKey::clientIp).toString();
|
||||||
|
if (!clientIp.isEmpty()) {
|
||||||
|
config.insert("deviceIpv4Address", clientIp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_active = new Tunnel(preAllocatedIfname, container, config, resolvedRemote, this);
|
m_active = new Tunnel(preAllocatedIfname, container, config, resolvedRemote, this);
|
||||||
wireTunnelSignals(m_active, /*isActive=*/true);
|
wireTunnelSignals(m_active, /*isActive=*/true);
|
||||||
@@ -553,6 +560,13 @@ void VpnConnection::startTunnelSwitch(DockerContainer container,
|
|||||||
if (VpnProtocol::isXrayBased(container)) {
|
if (VpnProtocol::isXrayBased(container)) {
|
||||||
config.insert("tunName", stagingIfname);
|
config.insert("tunName", stagingIfname);
|
||||||
config.insert("deviceIpv4Address", amnezia::protocols::xray::defaultLocalAddr);
|
config.insert("deviceIpv4Address", amnezia::protocols::xray::defaultLocalAddr);
|
||||||
|
} else if (VpnProtocol::isWireGuardBased(container)) {
|
||||||
|
const QString protoName = config.value("protocol").toString();
|
||||||
|
const QJsonObject wgConfig = config.value(protoName + "_config_data").toObject();
|
||||||
|
const QString clientIp = wgConfig.value(amnezia::configKey::clientIp).toString();
|
||||||
|
if (!clientIp.isEmpty()) {
|
||||||
|
config.insert("deviceIpv4Address", clientIp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
appendKillSwitchConfig(config);
|
appendKillSwitchConfig(config);
|
||||||
appendSplitTunnelingConfig(config);
|
appendSplitTunnelingConfig(config);
|
||||||
|
|||||||
Reference in New Issue
Block a user