diff --git a/client/core/utils/networkUtilities.cpp b/client/core/utils/networkUtilities.cpp index c61304c63..9b0a0ef6b 100644 --- a/client/core/utils/networkUtilities.cpp +++ b/client/core/utils/networkUtilities.cpp @@ -397,6 +397,9 @@ QPair NetworkUtilities::getGatewayAndIface() } if ((*gateway_address) && (*interface)) { + if (QString::fromUtf8(interface).startsWith("amn")) { + continue; + } qDebug() << "Gateway " << gateway_address << " for interface " << interface; break; } diff --git a/client/core/vpnTrafficGuard.cpp b/client/core/vpnTrafficGuard.cpp index bf4a701da..05ac0194d 100644 --- a/client/core/vpnTrafficGuard.cpp +++ b/client/core/vpnTrafficGuard.cpp @@ -79,12 +79,13 @@ void VpnTrafficGuard::setupRoutes(const QJsonObject &vpnConfiguration, const QSh } QString dns1 = vpnConfiguration.value(configKey::dns1).toString(); QString dns2 = vpnConfiguration.value(configKey::dns2).toString(); + const QString xrayIfname = vpnConfiguration.value("ifname").toString(); #ifdef Q_OS_MACOS if (!m_appSettingsRepository->isSitesSplitTunnelingEnabled() || m_appSettingsRepository->routeMode() != amnezia::RouteMode::VpnAllExceptSites) { - iface->routeAddList(protocol->vpnGateway(), QStringList() << dns1 << dns2); + iface->routeAddListVia(xrayIfname, protocol->vpnGateway(), QStringList() << dns1 << dns2); } #else - iface->routeAddList(protocol->vpnGateway(), QStringList() << dns1 << dns2); + iface->routeAddListVia(xrayIfname, protocol->vpnGateway(), QStringList() << dns1 << dns2); #endif if (m_appSettingsRepository->isSitesSplitTunnelingEnabled()) { @@ -99,8 +100,7 @@ void VpnTrafficGuard::setupRoutes(const QJsonObject &vpnConfiguration, const QSh addSplitTunnelRoutes(protocolPtr->vpnGateway(), m_appSettingsRepository->routeMode()); }); } else if (m_appSettingsRepository->routeMode() == amnezia::route_mode_ns::VpnAllExceptSites) { - iface->routeAddList(protocol->vpnGateway(), QStringList() << "0.0.0.0/1"); - iface->routeAddList(protocol->vpnGateway(), QStringList() << "128.0.0.0/1"); + iface->routeAddListVia(xrayIfname, protocol->vpnGateway(), QStringList() << "0.0.0.0/1" << "128.0.0.0/1"); iface->routeAddList(protocol->routeGateway(), QStringList() << remoteAddress); #ifdef Q_OS_MACOS @@ -141,7 +141,6 @@ void VpnTrafficGuard::addSplitTunnelRoutes(const QString &gw, amnezia::RouteMode iface->routeAddList(gw, ips); }); - // re-resolve domains for (const QString &site : sites) { const auto &cbResolv = [this, site, gw, mode, ips](const QHostInfo &hostInfo) { for (const QHostAddress &addr : hostInfo.addresses()) { @@ -238,7 +237,8 @@ void VpnTrafficGuard::applyKillSwitch(Tunnel* tunnel, const QString &gateway, co if (isXrayBased) { if (updatedConfig.value(configKey::splitTunnelType).toInt() == amnezia::route_mode_ns::VpnAllSites) { static const QStringList subnets = { "1.0.0.0/8", "2.0.0.0/7", "4.0.0.0/6", "8.0.0.0/5", "16.0.0.0/4", "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/1" }; - auto routeAddList = iface->routeAddList(gateway, subnets); + const QString xrayIfname = tunnel ? tunnel->ifname() : QString(); + auto routeAddList = iface->routeAddListVia(xrayIfname, gateway, subnets); if (!routeAddList.waitForFinished() || routeAddList.returnValue() != subnets.count()) { qCritical() << "Failed to set routes for TUN"; } diff --git a/client/vpnConnection.cpp b/client/vpnConnection.cpp index 58ea4d181..8783e73ca 100644 --- a/client/vpnConnection.cpp +++ b/client/vpnConnection.cpp @@ -253,6 +253,7 @@ void VpnConnection::connectToVpn(const QString &serverId, DockerContainer contai config.insert("deviceIpv4Address", clientIp); } } + m_vpnConfiguration = config; m_active = new Tunnel(preAllocatedIfname, container, config, resolvedRemote, this); wireTunnelSignals(m_active, /*isActive=*/true); wireDaemonReconnectSignals(); diff --git a/ipc/ipc_interface.rep b/ipc/ipc_interface.rep index e686f6221..f05630d63 100644 --- a/ipc/ipc_interface.rep +++ b/ipc/ipc_interface.rep @@ -10,6 +10,7 @@ class IpcInterface // Route functions SLOT( int routeAddList(const QString &gw, const QStringList &ips) ); + SLOT( int routeAddListVia(const QString &ifname, const QString &gw, const QStringList &ips) ); SLOT( bool clearSavedRoutes() ); SLOT( bool routeDeleteList(const QString &gw, const QStringList &ip) ); SLOT( bool addExclusionRoute(const QString &ifname, const QString &addr) ); diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index eb32f0e1c..c1c57a34d 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -97,6 +97,15 @@ int IpcServer::routeAddList(const QString &gw, const QStringList &ips) return Router::routeAddList(gw, ips); } +int IpcServer::routeAddListVia(const QString &ifname, const QString &gw, const QStringList &ips) +{ +#ifdef MZ_DEBUG + qDebug() << "IpcServer::routeAddListVia" << ifname; +#endif + + return Router::routeAddListVia(ifname, gw, ips); +} + bool IpcServer::clearSavedRoutes() { #ifdef MZ_DEBUG diff --git a/ipc/ipcserver.h b/ipc/ipcserver.h index 87c4439b5..d0efedf19 100644 --- a/ipc/ipcserver.h +++ b/ipc/ipcserver.h @@ -26,6 +26,7 @@ public: virtual int createPrivilegedProcess() override; virtual int routeAddList(const QString &gw, const QStringList &ips) override; + virtual int routeAddListVia(const QString &ifname, 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 &ifname, const QString &addr) override; diff --git a/service/server/router.cpp b/service/server/router.cpp index 8849d27b7..384828370 100644 --- a/service/server/router.cpp +++ b/service/server/router.cpp @@ -20,6 +20,16 @@ int Router::routeAddList(const QString &gw, const QStringList &ips) #endif } +int Router::routeAddListVia(const QString &ifname, const QString &gw, const QStringList &ips) +{ +#ifdef Q_OS_LINUX + return RouterLinux::Instance().routeAddListVia(ifname, gw, ips); +#else + Q_UNUSED(ifname) + return routeAddList(gw, ips); +#endif +} + bool Router::clearSavedRoutes() { #ifdef Q_OS_WIN diff --git a/service/server/router.h b/service/server/router.h index 2b42f9dc9..f2aff614d 100644 --- a/service/server/router.h +++ b/service/server/router.h @@ -17,6 +17,7 @@ class Router : public QObject Q_OBJECT public: static int routeAddList(const QString &gw, const QStringList &ips); + static int routeAddListVia(const QString &ifname, const QString &gw, const QStringList &ips); static bool clearSavedRoutes(); static int routeDeleteList(const QString &gw, const QStringList &ips); static bool flushDns(); diff --git a/service/server/router_linux.cpp b/service/server/router_linux.cpp index d2699d0c0..1b3655079 100644 --- a/service/server/router_linux.cpp +++ b/service/server/router_linux.cpp @@ -87,6 +87,34 @@ int RouterLinux::routeAddList(const QString &gw, const QStringList &ips) return cnt; } +int RouterLinux::routeAddListVia(const QString &ifname, const QString &gw, const QStringList &ips) +{ + if (ifname.isEmpty()) { + qWarning() << "routeAddListVia: empty ifname"; + return 0; + } + int cnt = 0; + for (const QString &ip : ips) { + QStringList args; + args << "route" << "replace" << ip; + if (!gw.isEmpty()) { + args << "via" << gw; + } + args << "dev" << ifname << "scope" << "link"; + + QProcess p; + p.setProcessChannelMode(QProcess::MergedChannels); + p.start("ip", args); + if (p.waitForFinished(2000) && p.exitCode() == 0) { + cnt++; + } else { + qWarning().noquote() << "routeAddListVia failed:" << ip << "via" << gw << "dev" << ifname + << "rc=" << p.exitCode() << "out=" << p.readAll(); + } + } + return cnt; +} + bool RouterLinux::clearSavedRoutes() { int temp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); diff --git a/service/server/router_linux.h b/service/server/router_linux.h index c862135ce..a3f108e3d 100644 --- a/service/server/router_linux.h +++ b/service/server/router_linux.h @@ -26,6 +26,7 @@ public: bool routeAdd(const QString &ip, const QString &gw, const int &sock); int routeAddList(const QString &gw, const QStringList &ips); + int routeAddListVia(const QString &ifname, const QString &gw, const QStringList &ips); bool clearSavedRoutes(); bool routeDelete(const QString &ip, const QString &gw, const int &sock); bool routeDeleteList(const QString &gw, const QStringList &ips);