Killswitch strict mode for Linux and MacOS

This commit is contained in:
Mykola Baibuz 2024-12-31 19:33:12 +02:00
parent d65273e43e
commit 08e5ff2eef
9 changed files with 97 additions and 14 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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<QHostAddress>& resolvers) );

View file

@ -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();

View file

@ -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;

View file

@ -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_$<UPPER_CASE:${MZ_PLATFORM_NAME}>")

View file

@ -1,5 +1,9 @@
#include "killswitch.h"
#include <QApplication>
#include <QHostAddress>
#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<SecureQSettings>(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;
@ -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);

View file

@ -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: