diff --git a/client/configurators/openvpn_configurator.cpp b/client/configurators/openvpn_configurator.cpp index ff2b4804..03adaa49 100644 --- a/client/configurators/openvpn_configurator.cpp +++ b/client/configurators/openvpn_configurator.cpp @@ -116,8 +116,8 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPairgetSitesSplitTunnelingEnabled()) { + + if (!m_settings->isSitesSplitTunnelingEnabled()) { config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n"); // Prevent ipv6 leak config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n"); diff --git a/client/daemon/daemon.cpp b/client/daemon/daemon.cpp index 30969de9..3e237e9c 100644 --- a/client/daemon/daemon.cpp +++ b/client/daemon/daemon.cpp @@ -374,6 +374,8 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) { return false; } + config.m_killSwitchEnabled = QVariant(obj.value("killSwitchOption").toString()).toBool(); + if (!obj.value("Jc").isNull()) { config.m_junkPacketCount = obj.value("Jc").toString(); } diff --git a/client/daemon/interfaceconfig.h b/client/daemon/interfaceconfig.h index f9869661..6a816f87 100644 --- a/client/daemon/interfaceconfig.h +++ b/client/daemon/interfaceconfig.h @@ -37,6 +37,7 @@ class InterfaceConfig { QList m_allowedIPAddressRanges; QStringList m_excludedAddresses; QStringList m_vpnDisabledApps; + bool m_killSwitchEnabled; #if defined(MZ_ANDROID) || defined(MZ_IOS) QString m_installationId; #endif diff --git a/client/mozilla/localsocketcontroller.cpp b/client/mozilla/localsocketcontroller.cpp index 877dfed5..0502facc 100644 --- a/client/mozilla/localsocketcontroller.cpp +++ b/client/mozilla/localsocketcontroller.cpp @@ -221,7 +221,9 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) { json.insert("excludedAddresses", jsExcludedAddresses); json.insert("vpnDisabledApps", splitTunnelApps); - + + json.insert(amnezia::config_key::killSwitchOption, rawConfig.value(amnezia::config_key::killSwitchOption)); + if (protocolName == amnezia::config_key::awg) { json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount)); json.insert(amnezia::config_key::junkPacketMinSize, wgConfig.value(amnezia::config_key::junkPacketMinSize)); diff --git a/client/platforms/linux/daemon/wireguardutilslinux.cpp b/client/platforms/linux/daemon/wireguardutilslinux.cpp index 2e328ae9..f7fc1496 100644 --- a/client/platforms/linux/daemon/wireguardutilslinux.cpp +++ b/client/platforms/linux/daemon/wireguardutilslinux.cpp @@ -136,24 +136,25 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) { if (err != 0) { logger.error() << "Interface configuration failed:" << strerror(err); } else { - FirewallParams params { }; - params.dnsServers.append(config.m_dnsServer); - if (config.m_allowedIPAddressRanges.at(0).toString() == "0.0.0.0/0"){ - params.blockAll = true; - if (config.m_excludedAddresses.size()) { - params.allowNets = true; - foreach (auto net, config.m_excludedAddresses) { - params.allowAddrs.append(net.toUtf8()); + if (config.m_killSwitchEnabled) { + FirewallParams params { }; + params.dnsServers.append(config.m_dnsServer); + if (config.m_allowedIPAddressRanges.at(0).toString() == "0.0.0.0/0"){ + params.blockAll = true; + if (config.m_excludedAddresses.size()) { + params.allowNets = true; + foreach (auto net, config.m_excludedAddresses) { + params.allowAddrs.append(net.toUtf8()); + } + } + } else { + params.blockNets = true; + foreach (auto net, config.m_allowedIPAddressRanges) { + params.blockAddrs.append(net.toString()); } } - } else { - params.blockNets = true; - foreach (auto net, config.m_allowedIPAddressRanges) { - params.blockAddrs.append(net.toString()); - } + applyFirewallRules(params); } - - applyFirewallRules(params); } return (err == 0); diff --git a/client/platforms/macos/daemon/wireguardutilsmacos.cpp b/client/platforms/macos/daemon/wireguardutilsmacos.cpp index 421c0f32..d47bb791 100644 --- a/client/platforms/macos/daemon/wireguardutilsmacos.cpp +++ b/client/platforms/macos/daemon/wireguardutilsmacos.cpp @@ -134,26 +134,26 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) { if (err != 0) { logger.error() << "Interface configuration failed:" << strerror(err); } else { - FirewallParams params { }; - params.dnsServers.append(config.m_dnsServer); - if (config.m_allowedIPAddressRanges.at(0).toString() == "0.0.0.0/0"){ - params.blockAll = true; - if (config.m_excludedAddresses.size()) { + if (config.m_killSwitchEnabled) { + FirewallParams params { }; + params.dnsServers.append(config.m_dnsServer); + if (config.m_allowedIPAddressRanges.at(0).toString() == "0.0.0.0/0"){ + params.blockAll = true; + if (config.m_excludedAddresses.size()) { params.allowNets = true; foreach (auto net, config.m_excludedAddresses) { - params.allowAddrs.append(net.toUtf8()); + params.allowAddrs.append(net.toUtf8()); } - } - } else { - params.blockNets = true; - foreach (auto net, config.m_allowedIPAddressRanges) { + } + } else { + params.blockNets = true; + foreach (auto net, config.m_allowedIPAddressRanges) { params.blockAddrs.append(net.toString()); + } } + applyFirewallRules(params); } - - applyFirewallRules(params); } - return (err == 0); } diff --git a/client/platforms/windows/daemon/wireguardutilswindows.cpp b/client/platforms/windows/daemon/wireguardutilswindows.cpp index 9885f065..a68551d7 100644 --- a/client/platforms/windows/daemon/wireguardutilswindows.cpp +++ b/client/platforms/windows/daemon/wireguardutilswindows.cpp @@ -116,10 +116,12 @@ bool WireguardUtilsWindows::addInterface(const InterfaceConfig& config) { m_luid = luid.Value; m_routeMonitor.setLuid(luid.Value); - // Enable the windows firewall - NET_IFINDEX ifindex; - ConvertInterfaceLuidToIndex(&luid, &ifindex); - WindowsFirewall::instance()->enableKillSwitch(ifindex); + if (config.m_killSwitchEnabled) { + // Enable the windows firewall + NET_IFINDEX ifindex; + ConvertInterfaceLuidToIndex(&luid, &ifindex); + WindowsFirewall::instance()->enableKillSwitch(ifindex); + } logger.debug() << "Registration completed"; return true; @@ -137,9 +139,10 @@ bool WireguardUtilsWindows::updatePeer(const InterfaceConfig& config) { QByteArray pskKey = QByteArray::fromBase64(qPrintable(config.m_serverPskKey)); - // Enable the windows firewall for this peer. - WindowsFirewall::instance()->enablePeerTraffic(config); - + if (config.m_killSwitchEnabled) { + // Enable the windows firewall for this peer. + WindowsFirewall::instance()->enablePeerTraffic(config); + } logger.debug() << "Configuring peer" << publicKey.toHex() << "via" << config.m_serverIpv4AddrIn; diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp index 61db69fc..04a18327 100644 --- a/client/protocols/openvpnprotocol.cpp +++ b/client/protocols/openvpnprotocol.cpp @@ -336,8 +336,11 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line) for (int i = 0; i < netInterfaces.size(); i++) { for (int j=0; j < netInterfaces.at(i).addressEntries().size(); j++) { + // killSwitch toggle if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) { - IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index()); + if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { + IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index()); + } m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index()); m_configData.insert("vpnGateway", m_vpnGateway); m_configData.insert("vpnServer", m_configData.value(amnezia::config_key::hostName).toString()); @@ -347,7 +350,10 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line) } #endif #if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) - IpcClient::Interface()->enableKillSwitch(m_configData, 0); + // killSwitch toggle + if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { + IpcClient::Interface()->enableKillSwitch(m_configData, 0); + } #endif qDebug() << QString("Set vpn local address %1, gw %2").arg(m_vpnLocalAddress).arg(vpnGateway()); } diff --git a/client/protocols/protocols_defs.h b/client/protocols/protocols_defs.h index feee11f3..90ef92fe 100644 --- a/client/protocols/protocols_defs.h +++ b/client/protocols/protocols_defs.h @@ -92,6 +92,8 @@ namespace amnezia constexpr char splitTunnelApps[] = "splitTunnelApps"; constexpr char appSplitTunnelType[] = "appSplitTunnelType"; + constexpr char killSwitchOption[] = "killSwitchOption"; + constexpr char crc[] = "crc"; constexpr char clientId[] = "clientId"; diff --git a/client/protocols/xrayprotocol.cpp b/client/protocols/xrayprotocol.cpp index 6bc92dd2..51812ce5 100644 --- a/client/protocols/xrayprotocol.cpp +++ b/client/protocols/xrayprotocol.cpp @@ -142,7 +142,6 @@ ErrorCode XrayProtocol::startTun2Sock() QThread::msleep(5000); IpcClient::Interface()->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr); IpcClient::Interface()->updateResolvers("utun22", dnsAddr); - IpcClient::Interface()->enableKillSwitch(m_configData, 0); #endif #ifdef Q_OS_WINDOWS QThread::msleep(15000); @@ -151,7 +150,12 @@ ErrorCode XrayProtocol::startTun2Sock() QThread::msleep(1000); IpcClient::Interface()->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr); IpcClient::Interface()->updateResolvers("tun2", dnsAddr); - IpcClient::Interface()->enableKillSwitch(m_configData, 0); +#endif +#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) + // killSwitch toggle + if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { + IpcClient::Interface()->enableKillSwitch(m_configData, 0); + } #endif if (m_routeMode == 0) { IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "0.0.0.0/1"); @@ -165,8 +169,11 @@ ErrorCode XrayProtocol::startTun2Sock() for (int i = 0; i < netInterfaces.size(); i++) { for (int j=0; j < netInterfaces.at(i).addressEntries().size(); j++) { + // killSwitch toggle if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) { - IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index()); + if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { + IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index()); + } m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index()); m_configData.insert("vpnGateway", m_vpnGateway); m_configData.insert("vpnServer", m_remoteAddress); @@ -200,6 +207,7 @@ void XrayProtocol::stop() { #if defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_MACOS) IpcClient::Interface()->disableKillSwitch(); + IpcClient::Interface()->StartRoutingIpv6(); #endif qDebug() << "XrayProtocol::stop()"; m_xrayProcess.terminate(); diff --git a/client/settings.cpp b/client/settings.cpp index c9aef207..8129b1e6 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -256,7 +256,7 @@ Settings::RouteMode Settings::routeMode() const return static_cast(value("Conf/routeMode", 0).toInt()); } -bool Settings::getSitesSplitTunnelingEnabled() const +bool Settings::isSitesSplitTunnelingEnabled() const { return value("Conf/sitesSplitTunnelingEnabled", false).toBool(); } @@ -415,7 +415,7 @@ void Settings::setVpnApps(AppsRouteMode mode, const QVector &a m_settings.sync(); } -bool Settings::getAppsSplitTunnelingEnabled() const +bool Settings::isAppsSplitTunnelingEnabled() const { return value("Conf/appsSplitTunnelingEnabled", false).toBool(); } @@ -425,6 +425,16 @@ void Settings::setAppsSplitTunnelingEnabled(bool enabled) setValue("Conf/appsSplitTunnelingEnabled", enabled); } +bool Settings::isKillSwitchEnabled() const +{ + return value("Conf/killSwitchEnabled", true).toBool(); +} + +void Settings::setKillSwitchEnabled(bool enabled) +{ + setValue("Conf/killSwitchEnabled", enabled); +} + QString Settings::getInstallationUuid(const bool needCreate) { auto uuid = value("Conf/installationUuid", "").toString(); diff --git a/client/settings.h b/client/settings.h index c1fd594f..74d1b4b9 100644 --- a/client/settings.h +++ b/client/settings.h @@ -115,7 +115,7 @@ public: RouteMode routeMode() const; void setRouteMode(RouteMode mode) { setValue("Conf/routeMode", mode); } - bool getSitesSplitTunnelingEnabled() const; + bool isSitesSplitTunnelingEnabled() const; void setSitesSplitTunnelingEnabled(bool enabled); QVariantMap vpnSites(RouteMode mode) const @@ -211,9 +211,11 @@ public: QVector getVpnApps(AppsRouteMode mode) const; void setVpnApps(AppsRouteMode mode, const QVector &apps); - bool getAppsSplitTunnelingEnabled() const; + bool isAppsSplitTunnelingEnabled() const; void setAppsSplitTunnelingEnabled(bool enabled); + bool isKillSwitchEnabled() const; + void setKillSwitchEnabled(bool enabled); QString getInstallationUuid(const bool needCreate); signals: diff --git a/client/ui/controllers/settingsController.cpp b/client/ui/controllers/settingsController.cpp index 24ed311c..31ca2607 100644 --- a/client/ui/controllers/settingsController.cpp +++ b/client/ui/controllers/settingsController.cpp @@ -223,3 +223,13 @@ void SettingsController::checkIfNeedDisableLogs() } } } + +bool SettingsController::isKillSwitchEnabled() +{ + return m_settings->isKillSwitchEnabled(); +} + +void SettingsController::toggleKillSwitch(bool enable) +{ + m_settings->setKillSwitchEnabled(enable); +} diff --git a/client/ui/controllers/settingsController.h b/client/ui/controllers/settingsController.h index b97ae3e0..ac84856d 100644 --- a/client/ui/controllers/settingsController.h +++ b/client/ui/controllers/settingsController.h @@ -63,6 +63,9 @@ public slots: bool isCameraPresent(); + bool isKillSwitchEnabled(); + void toggleKillSwitch(bool enable); + signals: void primaryDnsChanged(); void secondaryDnsChanged(); diff --git a/client/ui/models/appSplitTunnelingModel.cpp b/client/ui/models/appSplitTunnelingModel.cpp index 55db08b0..077efc12 100644 --- a/client/ui/models/appSplitTunnelingModel.cpp +++ b/client/ui/models/appSplitTunnelingModel.cpp @@ -5,7 +5,7 @@ AppSplitTunnelingModel::AppSplitTunnelingModel(std::shared_ptr settings, QObject *parent) : QAbstractListModel(parent), m_settings(settings) { - m_isSplitTunnelingEnabled = m_settings->getAppsSplitTunnelingEnabled(); + m_isSplitTunnelingEnabled = m_settings->isAppsSplitTunnelingEnabled(); m_currentRouteMode = m_settings->getAppsRouteMode(); if (m_currentRouteMode == Settings::VpnAllApps) { // for old split tunneling configs m_settings->setAppsRouteMode(static_cast(Settings::VpnAllExceptApps)); diff --git a/client/ui/models/sites_model.cpp b/client/ui/models/sites_model.cpp index cc3dd188..99d93618 100644 --- a/client/ui/models/sites_model.cpp +++ b/client/ui/models/sites_model.cpp @@ -3,7 +3,7 @@ SitesModel::SitesModel(std::shared_ptr settings, QObject *parent) : QAbstractListModel(parent), m_settings(settings) { - m_isSplitTunnelingEnabled = m_settings->getSitesSplitTunnelingEnabled(); + m_isSplitTunnelingEnabled = m_settings->isSitesSplitTunnelingEnabled(); m_currentRouteMode = m_settings->routeMode(); if (m_currentRouteMode == Settings::VpnAllSites) { // for old split tunneling configs m_settings->setRouteMode(static_cast(Settings::VpnOnlyForwardSites)); diff --git a/client/ui/qml/Pages2/PageSettingsBackup.qml b/client/ui/qml/Pages2/PageSettingsBackup.qml index 2a696a77..ffb5659d 100644 --- a/client/ui/qml/Pages2/PageSettingsBackup.qml +++ b/client/ui/qml/Pages2/PageSettingsBackup.qml @@ -149,10 +149,9 @@ PageType { var noButtonText = qsTr("Cancel") var yesButtonFunction = function() { - if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { + if (ConnectionController.isConnected) { PageController.showNotificationMessage(qsTr("Cannot restore backup settings during active connection")) - } else - { + } else { PageController.showBusyIndicator(true) SettingsController.restoreAppConfig(filePath) PageController.showBusyIndicator(false) diff --git a/client/ui/qml/Pages2/PageSettingsConnection.qml b/client/ui/qml/Pages2/PageSettingsConnection.qml index c732e6f2..421bbc95 100644 --- a/client/ui/qml/Pages2/PageSettingsConnection.qml +++ b/client/ui/qml/Pages2/PageSettingsConnection.qml @@ -130,6 +130,31 @@ PageType { DividerType { visible: root.isAppSplitTinnelingEnabled } + + SwitcherType { + Layout.fillWidth: true + Layout.margins: 16 + + text: qsTr("KillSwitch") + descriptionText: qsTr("Disables your internet if your encrypted VPN connection drops out for any reason.") + + checked: SettingsController.isKillSwitchEnabled() + checkable: !ConnectionController.isConnected + onCheckedChanged: { + if (checked !== SettingsController.isKillSwitchEnabled()) { + SettingsController.toggleKillSwitch(checked) + } + } + onClicked: { + if (!checkable) { + PageController.showNotificationMessage(qsTr("Cannot change killSwitch settings during active connection")) + } + } + } + + DividerType { + visible: GC.isDesktop() + } } } } diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index 323a4c27..791fb3ac 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -70,7 +70,7 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state) IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << dns1 << dns2); - if (m_settings->getSitesSplitTunnelingEnabled()) { + if (m_settings->isSitesSplitTunnelingEnabled()) { IpcClient::Interface()->routeDeleteList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0"); // qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << forwardIps.size(); if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { @@ -89,7 +89,7 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state) } else if (state == Vpn::ConnectionState::Error) { IpcClient::Interface()->flushDns(); - if (m_settings->getSitesSplitTunnelingEnabled()) { + if (m_settings->isSitesSplitTunnelingEnabled()) { if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { IpcClient::Interface()->clearSavedRoutes(); } @@ -237,15 +237,17 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede m_remoteAddress = credentials.hostName; emit connectionStateChanged(Vpn::ConnectionState::Connecting); + m_vpnConfiguration = vpnConfiguration; + #ifdef AMNEZIA_DESKTOP if (m_vpnProtocol) { disconnect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError); m_vpnProtocol->stop(); m_vpnProtocol.reset(); } + appendKillSwitchConfig(); #endif - m_vpnConfiguration = vpnConfiguration; appendSplitTunnelingConfig(); #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) @@ -282,6 +284,11 @@ void VpnConnection::createProtocolConnections() connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64))); } +void VpnConnection::appendKillSwitchConfig() +{ + m_vpnConfiguration.insert(config_key::killSwitchOption, QVariant(m_settings->isKillSwitchEnabled()).toString()); +} + void VpnConnection::appendSplitTunnelingConfig() { if (m_vpnConfiguration.value(config_key::configVersion).toInt()) { @@ -305,7 +312,7 @@ void VpnConnection::appendSplitTunnelingConfig() Settings::RouteMode routeMode = Settings::RouteMode::VpnAllSites; QJsonArray sitesJsonArray; - if (m_settings->getSitesSplitTunnelingEnabled()) { + if (m_settings->isSitesSplitTunnelingEnabled()) { routeMode = m_settings->routeMode(); auto sites = m_settings->getVpnIps(routeMode); @@ -325,7 +332,7 @@ void VpnConnection::appendSplitTunnelingConfig() Settings::AppsRouteMode appsRouteMode = Settings::AppsRouteMode::VpnAllApps; QJsonArray appsJsonArray; - if (m_settings->getAppsSplitTunnelingEnabled()) { + if (m_settings->isAppsSplitTunnelingEnabled()) { appsRouteMode = m_settings->getAppsRouteMode(); auto apps = m_settings->getVpnApps(appsRouteMode); diff --git a/client/vpnconnection.h b/client/vpnconnection.h index 33c1b67a..0160edce 100644 --- a/client/vpnconnection.h +++ b/client/vpnconnection.h @@ -94,6 +94,7 @@ private: void createProtocolConnections(); void appendSplitTunnelingConfig(); + void appendKillSwitchConfig(); }; #endif // VPNCONNECTION_H diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index 2f4e6296..c734912b 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -360,7 +360,11 @@ bool IpcServer::enablePeerTraffic(const QJsonObject &configStr) config.m_vpnDisabledApps.append(i.toString()); } - WindowsFirewall::instance()->enablePeerTraffic(config); + // killSwitch toggle + if (QVariant(configStr.value(amnezia::config_key::killSwitchOption).toString()).toBool()) { + WindowsFirewall::instance()->enablePeerTraffic(config); + } + WindowsDaemon::instance()->prepareActivation(config, inetAdapterIndex); WindowsDaemon::instance()->activateSplitTunnel(config, vpnAdapterIndex); return true;