diff --git a/client/platforms/linux/daemon/wireguardutilslinux.cpp b/client/platforms/linux/daemon/wireguardutilslinux.cpp index 460a7fe1..81ae20db 100644 --- a/client/platforms/linux/daemon/wireguardutilslinux.cpp +++ b/client/platforms/linux/daemon/wireguardutilslinux.cpp @@ -17,6 +17,8 @@ #include "leakdetector.h" #include "logger.h" +#include "killswitch.h" + constexpr const int WG_TUN_PROC_TIMEOUT = 5000; constexpr const char* WG_RUNTIME_DIR = "/var/run/amneziawg"; @@ -182,7 +184,7 @@ bool WireguardUtilsLinux::deleteInterface() { QFile::remove(wgRuntimeDir.filePath(QString(WG_INTERFACE) + ".name")); // double-check + ensure our firewall is installed and enabled - LinuxFirewall::uninstall(); + KillSwitch::instance()->disableKillSwitch(); return true; } diff --git a/client/platforms/macos/daemon/wireguardutilsmacos.cpp b/client/platforms/macos/daemon/wireguardutilsmacos.cpp index e2802ebc..4e0e994e 100644 --- a/client/platforms/macos/daemon/wireguardutilsmacos.cpp +++ b/client/platforms/macos/daemon/wireguardutilsmacos.cpp @@ -15,6 +15,8 @@ #include "leakdetector.h" #include "logger.h" +#include "killswitch.h" + constexpr const int WG_TUN_PROC_TIMEOUT = 5000; constexpr const char* WG_RUNTIME_DIR = "/var/run/amneziawg"; @@ -180,7 +182,7 @@ bool WireguardUtilsMacos::deleteInterface() { QFile::remove(wgRuntimeDir.filePath(QString(WG_INTERFACE) + ".name")); // double-check + ensure our firewall is installed and enabled - MacOSFirewall::uninstall(); + KillSwitch::instance()->disableKillSwitch(); return true; } diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp index 4c2feb52..1721a45a 100644 --- a/client/protocols/openvpnprotocol.cpp +++ b/client/protocols/openvpnprotocol.cpp @@ -171,6 +171,11 @@ ErrorCode OpenVpnProtocol::start() return lastError(); } +#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) + IpcClient::Interface()->allowTrafficTo(QStringList(NetworkUtilities::getIPAddress( + m_configData.value(amnezia::config_key::hostName).toString()))); +#endif + // Detect default gateway #ifdef Q_OS_MAC QProcess p; diff --git a/ipc/ipc_interface.rep b/ipc/ipc_interface.rep index 77bdeadd..0ce7626a 100644 --- a/ipc/ipc_interface.rep +++ b/ipc/ipc_interface.rep @@ -30,6 +30,7 @@ class IpcInterface SLOT( bool disableKillSwitch() ); SLOT( bool disableAllTraffic() ); + SLOT( bool allowTrafficTo( const QStringList ranges ) ); SLOT( bool enablePeerTraffic( const QJsonObject &configStr) ); SLOT( bool enableKillSwitch( const QJsonObject &excludeAddr, int vpnAdapterIndex) ); SLOT( bool updateResolvers(const QString& ifname, const QList& resolvers) ); diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index 4e6bb4fe..e3f729a0 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -179,6 +179,11 @@ void IpcServer::setLogsEnabled(bool enabled) } } +bool IpcServer::allowTrafficTo(QStringList ranges) +{ + return KillSwitch::instance()->allowTrafficTo(ranges); +} + bool IpcServer::disableAllTraffic() { return KillSwitch::instance()->disableAllTraffic(); diff --git a/ipc/ipcserver.h b/ipc/ipcserver.h index 0ab98467..452534cd 100644 --- a/ipc/ipcserver.h +++ b/ipc/ipcserver.h @@ -35,6 +35,7 @@ public: virtual void StartRoutingIpv6() override; virtual void StopRoutingIpv6() override; virtual bool disableAllTraffic() override; + virtual bool allowTrafficTo(QStringList ranges) override; virtual bool enablePeerTraffic(const QJsonObject &configStr) override; virtual bool enableKillSwitch(const QJsonObject &excludeAddr, int vpnAdapterIndex) override; virtual bool disableKillSwitch() override; diff --git a/service/server/CMakeLists.txt b/service/server/CMakeLists.txt index 0189ee08..863a918c 100644 --- a/service/server/CMakeLists.txt +++ b/service/server/CMakeLists.txt @@ -258,6 +258,9 @@ if(APPLE) ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/macos/daemon/wireguardutilsmacos.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/macos/daemon/macosfirewall.cpp ) + + set(LIBS ${OPENSSL_LIB_CRYPTO_PATH} qt6keychain) + endif() if(LINUX) @@ -288,6 +291,9 @@ if(LINUX) ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/linuxroutemonitor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/linuxfirewall.cpp ) + + set(LIBS ${OPENSSL_LIB_CRYPTO_PATH} qt6keychain -static-libstdc++ -static-libgcc -ldl) + endif() include(${CMAKE_CURRENT_LIST_DIR}/../src/qtservice.cmake) @@ -300,6 +306,7 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) + add_executable(${PROJECT} ${SOURCES} ${HEADERS}) target_link_libraries(${PROJECT} PRIVATE Qt6::Core Qt6::Widgets Qt6::Network Qt6::RemoteObjects Qt6::Core5Compat Qt6::DBus ${LIBS}) target_compile_definitions(${PROJECT} PRIVATE "MZ_$") diff --git a/service/server/killswitch.cpp b/service/server/killswitch.cpp index 60fab803..1e823e13 100644 --- a/service/server/killswitch.cpp +++ b/service/server/killswitch.cpp @@ -1,5 +1,9 @@ #include "killswitch.h" + +#include +#include + #include "../client/protocols/protocols_defs.h" #include "qjsonarray.h" #include "version.h" @@ -29,11 +33,24 @@ KillSwitch* KillSwitch::instance() bool KillSwitch::init() { +#ifdef Q_OS_WIN WindowsFirewall::instance()->init(); +#endif +#ifdef Q_OS_LINUX + if (!LinuxFirewall::isInstalled()) { + LinuxFirewall::install(); + } +#endif +#ifdef Q_OS_MACOS + if (!MacOSFirewall::isInstalled()) { + MacOSFirewall::install(); + } +#endif m_appSettigns = QSharedPointer(new SecureQSettings(ORGANIZATION_NAME, APPLICATION_NAME, nullptr)); if (isStrictKillSwitchEnabled()) { return disableAllTraffic(); } + return true; } bool KillSwitch::isStrictKillSwitchEnabled() @@ -42,21 +59,46 @@ bool KillSwitch::isStrictKillSwitchEnabled() } bool KillSwitch::disableKillSwitch() { +#ifdef Q_OS_LINUX if (isStrictKillSwitchEnabled()) { - return disableAllTraffic(); + LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("000.allowLoopback"), true); + LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("100.blockAll"), true); + LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("110.allowNets"), false); + LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("120.blockNets"), false); + LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("200.allowVPN"), false); + LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv6, QStringLiteral("250.blockIPv6"), true); + LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("290.allowDHCP"), false); + LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("300.allowLAN"), false); + LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("310.blockDNS"), false); + LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("320.allowDNS"), false); + LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("400.allowPIA"), false); + } else { + LinuxFirewall::uninstall(); } +#endif + +#ifdef Q_OS_MACOS + if (isStrictKillSwitchEnabled()) { + MacOSFirewall::setAnchorEnabled(QStringLiteral("000.allowLoopback"), true); + MacOSFirewall::setAnchorEnabled(QStringLiteral("100.blockAll"), true); + MacOSFirewall::setAnchorEnabled(QStringLiteral("110.allowNets"), false); + MacOSFirewall::setAnchorEnabled(QStringLiteral("120.blockNets"), false); + MacOSFirewall::setAnchorEnabled(QStringLiteral("200.allowVPN"), false); + MacOSFirewall::setAnchorEnabled(QStringLiteral("250.blockIPv6"), true); + MacOSFirewall::setAnchorEnabled(QStringLiteral("290.allowDHCP"), false); + MacOSFirewall::setAnchorEnabled(QStringLiteral("300.allowLAN"), false); + MacOSFirewall::setAnchorEnabled(QStringLiteral("310.blockDNS"), false); + } else { + MacOSFirewall::uninstall(); + } +#endif #ifdef Q_OS_WIN return WindowsFirewall::instance()->allowAllTraffic(); #endif -#ifdef Q_OS_LINUX - LinuxFirewall::uninstall(); -#endif + return true; -#ifdef Q_OS_MACOS - MacOSFirewall::uninstall(); -#endif } bool KillSwitch::disableAllTraffic() { @@ -69,6 +111,7 @@ bool KillSwitch::disableAllTraffic() { } LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("100.blockAll"), true); LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("000.allowLoopback"), true); + LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv6, QStringLiteral("250.blockIPv6"), true); #endif #ifdef Q_OS_MACOS // double-check + ensure our firewall is installed and enabled. This is necessary as @@ -78,10 +121,26 @@ bool KillSwitch::disableAllTraffic() { MacOSFirewall::ensureRootAnchorPriority(); MacOSFirewall::setAnchorEnabled(QStringLiteral("100.blockAll"), true); MacOSFirewall::setAnchorEnabled(QStringLiteral("000.allowLoopback"), true); + MacOSFirewall::setAnchorEnabled(QStringLiteral("250.blockIPv6"), true); #endif return true; } +bool KillSwitch::allowTrafficTo(const QStringList &ranges) { + +#ifdef Q_OS_LINUX + LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("110.allowNets"), true); + LinuxFirewall::updateAllowNets(ranges); +#endif + +#ifdef Q_OS_MACOS + MacOSFirewall::setAnchorEnabled(QStringLiteral("110.allowNets"), true); + MacOSFirewall::setAnchorTable(QStringLiteral("110.allowNets"), true, QStringLiteral("allownets"), ranges); +#endif + + return true; +} + bool KillSwitch::enablePeerTraffic(const QJsonObject &configStr) { #ifdef Q_OS_WIN InterfaceConfig config; @@ -95,7 +154,7 @@ bool KillSwitch::enablePeerTraffic(const QJsonObject &configStr) { int splitTunnelType = configStr.value("splitTunnelType").toInt(); QJsonArray splitTunnelSites = configStr.value("splitTunnelSites").toArray(); - // Use APP split tunnel + // Use APP split tunnel if (splitTunnelType == 0 || splitTunnelType == 2) { config.m_allowedIPAddressRanges.append(IPAddress(QHostAddress("0.0.0.0"), 0)); config.m_allowedIPAddressRanges.append(IPAddress(QHostAddress("::"), 0)); @@ -139,8 +198,7 @@ bool KillSwitch::enablePeerTraffic(const QJsonObject &configStr) { return true; } - -bool KillSwitch::enableKillSwitch(const QJsonObject &excludeAddr, int vpnAdapterIndex) { +bool KillSwitch::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIndex) { #ifdef Q_OS_WIN return WindowsFirewall::instance()->enableKillSwitch(vpnAdapterIndex); #endif @@ -154,7 +212,6 @@ bool KillSwitch::enableKillSwitch(const QJsonObject &excludeAddr, int vpnAdapter QStringList allownets; QStringList blocknets; - if (splitTunnelType == 0) { blockAll = true; allowNets = true; @@ -177,6 +234,8 @@ bool KillSwitch::enableKillSwitch(const QJsonObject &excludeAddr, int vpnAdapter #ifdef Q_OS_LINUX if (!LinuxFirewall::isInstalled()) { LinuxFirewall::install(); + } + // double-check + ensure our firewall is installed and enabled LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("000.allowLoopback"), true); LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("100.blockAll"), blockAll); diff --git a/service/server/killswitch.h b/service/server/killswitch.h index 36e64622..d6fc0a0e 100644 --- a/service/server/killswitch.h +++ b/service/server/killswitch.h @@ -15,7 +15,8 @@ public: bool disableKillSwitch(); bool disableAllTraffic(); bool enablePeerTraffic( const QJsonObject &configStr); - bool enableKillSwitch( const QJsonObject &excludeAddr, int vpnAdapterIndex); + bool enableKillSwitch( const QJsonObject &configStr, int vpnAdapterIndex); + bool allowTrafficTo(const QStringList &ranges); bool isStrictKillSwitchEnabled(); private: