mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-24 02:00:24 +07:00
feat: per-tunnel Windows firewall for seamless WG switch
This commit is contained in:
@@ -79,7 +79,7 @@ GatewayController::EncryptedRequestData GatewayController::prepareRequest(const
|
|||||||
QString ip = NetworkUtilities::getIPAddress(host);
|
QString ip = NetworkUtilities::getIPAddress(host);
|
||||||
if (!ip.isEmpty()) {
|
if (!ip.isEmpty()) {
|
||||||
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||||
QRemoteObjectPendingReply<bool> reply = iface->addKillSwitchAllowedRange(QStringList { ip });
|
QRemoteObjectPendingReply<bool> reply = iface->addKillSwitchAllowedRange(QString(), QStringList { ip });
|
||||||
if (!reply.waitForFinished(1000) || !reply.returnValue())
|
if (!reply.waitForFinished(1000) || !reply.returnValue())
|
||||||
qWarning() << "GatewayController::prepareRequest(): Failed to execute remote addKillSwitchAllowedRange call";
|
qWarning() << "GatewayController::prepareRequest(): Failed to execute remote addKillSwitchAllowedRange call";
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ public:
|
|||||||
State state() const { return m_state; }
|
State state() const { return m_state; }
|
||||||
QSharedPointer<VpnProtocol> protocol() const { return m_protocol; }
|
QSharedPointer<VpnProtocol> protocol() const { return m_protocol; }
|
||||||
|
|
||||||
|
const QString& handoverIfname() const { return m_handoverIfname; }
|
||||||
|
void setHandoverIfname(const QString& ifname) { m_handoverIfname = ifname; }
|
||||||
|
void clearHandoverIfname() { m_handoverIfname.clear(); }
|
||||||
|
|
||||||
virtual void prepare();
|
virtual void prepare();
|
||||||
virtual void commit();
|
virtual void commit();
|
||||||
virtual void deactivate();
|
virtual void deactivate();
|
||||||
@@ -61,6 +65,7 @@ protected:
|
|||||||
|
|
||||||
QString m_ifname;
|
QString m_ifname;
|
||||||
QString m_remoteAddress;
|
QString m_remoteAddress;
|
||||||
|
QString m_handoverIfname;
|
||||||
amnezia::DockerContainer m_container;
|
amnezia::DockerContainer m_container;
|
||||||
QJsonObject m_config;
|
QJsonObject m_config;
|
||||||
QSharedPointer<VpnProtocol> m_protocol;
|
QSharedPointer<VpnProtocol> m_protocol;
|
||||||
|
|||||||
@@ -31,37 +31,27 @@ void VpnTrafficGuard::setConfig(const QJsonObject &config)
|
|||||||
m_config = config;
|
m_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VpnTrafficGuard::allowEndpoint(const QString &remoteAddress)
|
bool VpnTrafficGuard::allowEndpoint(const QString &remoteAddress, const QString &ifname)
|
||||||
{
|
{
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
if (remoteAddress.isEmpty()) {
|
if (remoteAddress.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!m_allowedEndpoints.contains(remoteAddress)) {
|
if (m_allowedEndpoints.contains(remoteAddress)) {
|
||||||
m_allowedEndpoints.append(remoteAddress);
|
return true;
|
||||||
}
|
}
|
||||||
|
m_allowedEndpoints.append(remoteAddress);
|
||||||
return IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
return IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||||
QRemoteObjectPendingReply<bool> reply = iface->addKillSwitchAllowedRange(QStringList(remoteAddress));
|
QRemoteObjectPendingReply<bool> reply = iface->addKillSwitchAllowedRange(ifname, QStringList(remoteAddress));
|
||||||
return reply.waitForFinished(1000) && reply.returnValue();
|
return reply.waitForFinished(1000) && reply.returnValue();
|
||||||
});
|
});
|
||||||
#else
|
#else
|
||||||
Q_UNUSED(remoteAddress)
|
Q_UNUSED(remoteAddress)
|
||||||
|
Q_UNUSED(ifname)
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void VpnTrafficGuard::revokeEndpoint(const QString &remoteAddress)
|
|
||||||
{
|
|
||||||
#ifdef AMNEZIA_DESKTOP
|
|
||||||
m_allowedEndpoints.removeAll(remoteAddress);
|
|
||||||
IpcClient::withInterface([this](QSharedPointer<IpcInterfaceReplica> iface) {
|
|
||||||
iface->resetKillSwitchAllowedRange(m_allowedEndpoints);
|
|
||||||
});
|
|
||||||
#else
|
|
||||||
Q_UNUSED(remoteAddress)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void VpnTrafficGuard::setupRoutes(const QJsonObject &vpnConfiguration, const QSharedPointer<VpnProtocol> &protocol, const QString &remoteAddress)
|
void VpnTrafficGuard::setupRoutes(const QJsonObject &vpnConfiguration, const QSharedPointer<VpnProtocol> &protocol, const QString &remoteAddress)
|
||||||
{
|
{
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
@@ -175,9 +165,29 @@ void VpnTrafficGuard::addSplitTunnelRoutes(const QString &gw, amnezia::RouteMode
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void VpnTrafficGuard::applyFirewall(const QString &gateway, const QString &localAddress)
|
void VpnTrafficGuard::finishFirewallHandover(Tunnel* tunnel)
|
||||||
|
{
|
||||||
|
#if defined(AMNEZIA_DESKTOP) && defined(Q_OS_WIN)
|
||||||
|
if (!tunnel) return;
|
||||||
|
const QString handoverIfname = tunnel->handoverIfname();
|
||||||
|
if (handoverIfname.isEmpty() || handoverIfname == tunnel->ifname()) {
|
||||||
|
tunnel->clearHandoverIfname();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||||
|
iface->disableKillSwitchForTunnel(handoverIfname, QStringList());
|
||||||
|
});
|
||||||
|
tunnel->clearHandoverIfname();
|
||||||
|
#else
|
||||||
|
Q_UNUSED(tunnel)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void VpnTrafficGuard::applyKillSwitch(Tunnel* tunnel, const QString &gateway, const QString &localAddress)
|
||||||
{
|
{
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
|
finishFirewallHandover(tunnel);
|
||||||
|
|
||||||
QJsonObject updatedConfig = m_config;
|
QJsonObject updatedConfig = m_config;
|
||||||
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
@@ -213,10 +223,10 @@ void VpnTrafficGuard::applyFirewall(const QString &gateway, const QString &local
|
|||||||
NetworkUtilities::getIPAddress(updatedConfig.value(amnezia::configKey::hostName).toString()));
|
NetworkUtilities::getIPAddress(updatedConfig.value(amnezia::configKey::hostName).toString()));
|
||||||
QRemoteObjectPendingReply<bool> reply = iface->enableKillSwitch(updatedConfig, 0);
|
QRemoteObjectPendingReply<bool> reply = iface->enableKillSwitch(updatedConfig, 0);
|
||||||
//TODO: why it takes so long?
|
//TODO: why it takes so long?
|
||||||
if (!reply.waitForFinished(5000) || !reply.returnValue()) {
|
if (!reply.waitForFinished(1000) || !reply.returnValue()) {
|
||||||
qWarning() << "VpnTrafficGuard::applyFirewall: Failed to enable killswitch";
|
qWarning() << "VpnTrafficGuard::applyKillSwitch: Failed to enable killswitch";
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "VpnTrafficGuard::applyFirewall: Successfully enabled killswitch";
|
qDebug() << "VpnTrafficGuard::applyKillSwitch: Successfully enabled killswitch";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -250,7 +260,7 @@ void VpnTrafficGuard::flushAll()
|
|||||||
QRemoteObjectPendingReply<bool> reply = iface->disableKillSwitch();
|
QRemoteObjectPendingReply<bool> reply = iface->disableKillSwitch();
|
||||||
m_allowedEndpoints.clear();
|
m_allowedEndpoints.clear();
|
||||||
//TODO: why it takes so long?
|
//TODO: why it takes so long?
|
||||||
if (!reply.waitForFinished(5000) || !reply.returnValue()) {
|
if (!reply.waitForFinished(1000) || !reply.returnValue()) {
|
||||||
qWarning() << "VpnTrafficGuard::flushAll: Failed to disable killswitch";
|
qWarning() << "VpnTrafficGuard::flushAll: Failed to disable killswitch";
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "VpnTrafficGuard::flushAll: Successfully disabled killswitch";
|
qDebug() << "VpnTrafficGuard::flushAll: Successfully disabled killswitch";
|
||||||
@@ -318,7 +328,7 @@ void VpnTrafficGuard::reserve(Tunnel* tunnel)
|
|||||||
{
|
{
|
||||||
if (!tunnel) return;
|
if (!tunnel) return;
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
allowEndpoint(tunnel->remoteAddress());
|
allowEndpoint(tunnel->remoteAddress(), tunnel->ifname());
|
||||||
#else
|
#else
|
||||||
Q_UNUSED(tunnel)
|
Q_UNUSED(tunnel)
|
||||||
#endif
|
#endif
|
||||||
@@ -327,8 +337,12 @@ void VpnTrafficGuard::reserve(Tunnel* tunnel)
|
|||||||
void VpnTrafficGuard::release(Tunnel* tunnel)
|
void VpnTrafficGuard::release(Tunnel* tunnel)
|
||||||
{
|
{
|
||||||
if (!tunnel) return;
|
if (!tunnel) return;
|
||||||
|
disconnect(tunnel, nullptr, this, nullptr);
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
revokeEndpoint(tunnel->remoteAddress());
|
m_allowedEndpoints.removeAll(tunnel->remoteAddress());
|
||||||
|
IpcClient::withInterface([this, &tunnel](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||||
|
iface->disableKillSwitchForTunnel(tunnel->ifname(), m_allowedEndpoints);
|
||||||
|
});
|
||||||
#else
|
#else
|
||||||
Q_UNUSED(tunnel)
|
Q_UNUSED(tunnel)
|
||||||
#endif
|
#endif
|
||||||
@@ -396,6 +410,17 @@ void VpnTrafficGuard::commit(Tunnel* tunnel)
|
|||||||
{
|
{
|
||||||
if (!tunnel) return;
|
if (!tunnel) return;
|
||||||
applyPolicy(tunnel);
|
applyPolicy(tunnel);
|
||||||
|
connect(tunnel, &Tunnel::activated, this, [this, tunnel] {
|
||||||
|
if (auto p = tunnel->protocol()) {
|
||||||
|
applyKillSwitch(tunnel, p->vpnGateway(), p->vpnLocalAddress());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
connect(tunnel, &Tunnel::addressesUpdated, this,
|
||||||
|
[this, tunnel](const QString& gw, const QString& la) {
|
||||||
|
applyKillSwitch(tunnel, gw, la);
|
||||||
|
});
|
||||||
|
#endif
|
||||||
tunnel->commit();
|
tunnel->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,11 +435,18 @@ void VpnTrafficGuard::tearDown(Tunnel* tunnel)
|
|||||||
void VpnTrafficGuard::swap(Tunnel* from, Tunnel* to)
|
void VpnTrafficGuard::swap(Tunnel* from, Tunnel* to)
|
||||||
{
|
{
|
||||||
if (!to) return;
|
if (!to) return;
|
||||||
applyPolicy(to);
|
|
||||||
to->commit();
|
|
||||||
if (from) {
|
if (from) {
|
||||||
|
to->setHandoverIfname(from->ifname());
|
||||||
|
}
|
||||||
|
commit(to);
|
||||||
|
if (from) {
|
||||||
|
m_allowedEndpoints.removeAll(from->remoteAddress());
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
|
IpcClient::withInterface([this](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||||
|
iface->resetKillSwitchAllowedRange(m_allowedEndpoints);
|
||||||
|
});
|
||||||
|
#endif
|
||||||
revokePolicy(from);
|
revokePolicy(from);
|
||||||
release(from);
|
|
||||||
from->deactivate();
|
from->deactivate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,8 @@ public:
|
|||||||
const QString &remoteAddress);
|
const QString &remoteAddress);
|
||||||
|
|
||||||
void flushAll();
|
void flushAll();
|
||||||
bool allowEndpoint(const QString &remoteAddress);
|
bool allowEndpoint(const QString &remoteAddress, const QString &ifname = QString());
|
||||||
void revokeEndpoint(const QString &remoteAddress);
|
void applyKillSwitch(Tunnel* tunnel, const QString &vpnGateway, const QString &vpnLocalAddress);
|
||||||
void applyFirewall(const QString &vpnGateway, const QString &vpnLocalAddress);
|
|
||||||
|
|
||||||
void reserve(Tunnel* tunnel);
|
void reserve(Tunnel* tunnel);
|
||||||
void release(Tunnel* tunnel);
|
void release(Tunnel* tunnel);
|
||||||
@@ -36,6 +35,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void addSplitTunnelRoutes(const QString &gateway, amnezia::RouteMode mode);
|
void addSplitTunnelRoutes(const QString &gateway, amnezia::RouteMode mode);
|
||||||
|
void finishFirewallHandover(Tunnel* tunnel);
|
||||||
SecureAppSettingsRepository* m_appSettingsRepository;
|
SecureAppSettingsRepository* m_appSettingsRepository;
|
||||||
QJsonObject m_config;
|
QJsonObject m_config;
|
||||||
bool m_ipv6RoutingStopped = false;
|
bool m_ipv6RoutingStopped = false;
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ bool WindowsFirewall::initSublayer() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WindowsFirewall::enableInterface(int vpnAdapterIndex) {
|
bool WindowsFirewall::enableInterface(int vpnAdapterIndex, const QString& ifname) {
|
||||||
// Checks if the FW_Rule was enabled succesfully,
|
// Checks if the FW_Rule was enabled succesfully,
|
||||||
// disables the whole killswitch and returns false if not.
|
// disables the whole killswitch and returns false if not.
|
||||||
#define FW_OK(rule) \
|
#define FW_OK(rule) \
|
||||||
@@ -182,31 +182,39 @@ bool WindowsFirewall::enableInterface(int vpnAdapterIndex) {
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info() << "Enabling Killswitch Using Adapter:" << vpnAdapterIndex;
|
logger.info() << "Enabling Killswitch Using Adapter:" << vpnAdapterIndex
|
||||||
if (vpnAdapterIndex < 0)
|
<< "ifname:" << ifname;
|
||||||
{
|
|
||||||
|
QList<uint64_t>& perTunnel = ifname.isEmpty() ? m_globalRules
|
||||||
|
: m_tunnelRules[ifname];
|
||||||
|
if (vpnAdapterIndex < 0) {
|
||||||
IPAddress allv4("0.0.0.0/0");
|
IPAddress allv4("0.0.0.0/0");
|
||||||
if (!blockTrafficTo(allv4, MED_WEIGHT,
|
if (!blockTrafficTo(allv4, MED_WEIGHT, "Block Internet", perTunnel)) {
|
||||||
"Block Internet", "killswitch")) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
IPAddress allv6("::/0");
|
IPAddress allv6("::/0");
|
||||||
if (!blockTrafficTo(allv6, MED_WEIGHT,
|
if (!blockTrafficTo(allv6, MED_WEIGHT, "Block Internet", perTunnel)) {
|
||||||
"Block Internet", "killswitch")) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
FW_OK(allowTrafficOfAdapter(vpnAdapterIndex, MED_WEIGHT,
|
FW_OK(allowTrafficOfAdapter(vpnAdapterIndex, MED_WEIGHT,
|
||||||
"Allow usage of VPN Adapter"));
|
"Allow usage of VPN Adapter", perTunnel));
|
||||||
FW_OK(allowDHCPTraffic(MED_WEIGHT, "Allow DHCP Traffic"));
|
}
|
||||||
FW_OK(allowHyperVTraffic(MAX_WEIGHT, "Allow Hyper-V Traffic"));
|
|
||||||
FW_OK(allowTrafficForAppOnAll(getCurrentPath(), MAX_WEIGHT,
|
|
||||||
"Allow all for AmneziaVPN.exe"));
|
|
||||||
FW_OK(blockTrafficOnPort(53, MED_WEIGHT, "Block all DNS"));
|
|
||||||
FW_OK(allowLoopbackTraffic(MED_WEIGHT,
|
|
||||||
"Allow Loopback traffic on device %1"));
|
|
||||||
|
|
||||||
logger.debug() << "Killswitch on! Rules:" << m_activeRules.length();
|
if (m_globalRules.isEmpty()) {
|
||||||
|
FW_OK(allowDHCPTraffic(MED_WEIGHT, "Allow DHCP Traffic", m_globalRules));
|
||||||
|
FW_OK(allowHyperVTraffic(MAX_WEIGHT, "Allow Hyper-V Traffic", m_globalRules));
|
||||||
|
FW_OK(allowTrafficForAppOnAll(getCurrentPath(), MAX_WEIGHT,
|
||||||
|
"Allow all for AmneziaVPN.exe", m_globalRules));
|
||||||
|
FW_OK(blockTrafficOnPort(53, MED_WEIGHT, "Block all DNS", m_globalRules));
|
||||||
|
FW_OK(allowLoopbackTraffic(MED_WEIGHT,
|
||||||
|
"Allow Loopback traffic on device %1",
|
||||||
|
m_globalRules));
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug() << "Killswitch on! Globals:" << m_globalRules.length()
|
||||||
|
<< "Tunnel[" << ifname
|
||||||
|
<< "]:" << m_tunnelRules.value(ifname).length();
|
||||||
return true;
|
return true;
|
||||||
#undef FW_OK
|
#undef FW_OK
|
||||||
}
|
}
|
||||||
@@ -226,7 +234,8 @@ bool WindowsFirewall::enableLanBypass(const QList<IPAddress>& ranges) {
|
|||||||
|
|
||||||
// Blocking unprotected traffic
|
// Blocking unprotected traffic
|
||||||
for (const IPAddress& prefix : ranges) {
|
for (const IPAddress& prefix : ranges) {
|
||||||
if (!allowTrafficTo(prefix, LOW_WEIGHT + 1, "Allow LAN bypass traffic")) {
|
if (!allowTrafficTo(prefix, LOW_WEIGHT + 1, "Allow LAN bypass traffic",
|
||||||
|
m_globalRules)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,7 +251,10 @@ bool WindowsFirewall::enableLanBypass(const QList<IPAddress>& ranges) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allow unprotected traffic sent to the following address ranges.
|
// Allow unprotected traffic sent to the following address ranges.
|
||||||
bool WindowsFirewall::allowTrafficRange(const QStringList& ranges) {
|
bool WindowsFirewall::allowTrafficRange(const QStringList& ranges, const QString& ifname) {
|
||||||
|
QList<uint64_t>& target = ifname.isEmpty() ? m_globalRules
|
||||||
|
: m_tunnelRules[ifname];
|
||||||
|
|
||||||
// Start the firewall transaction
|
// Start the firewall transaction
|
||||||
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
|
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
|
||||||
if (result != ERROR_SUCCESS) {
|
if (result != ERROR_SUCCESS) {
|
||||||
@@ -255,8 +267,9 @@ bool WindowsFirewall::allowTrafficRange(const QStringList& ranges) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const QString& addr : ranges) {
|
for (const QString& addr : ranges) {
|
||||||
logger.debug() << "Allow killswitch exclude: " << addr;
|
logger.debug() << "Allow killswitch exclude: " << addr << "ifname:" << ifname;
|
||||||
if (!allowTrafficTo(QHostAddress(addr), HIGH_WEIGHT, "Allow killswitch bypass traffic")) {
|
if (!allowTrafficTo(QHostAddress(addr), HIGH_WEIGHT,
|
||||||
|
"Allow killswitch bypass traffic", target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,6 +286,10 @@ bool WindowsFirewall::allowTrafficRange(const QStringList& ranges) {
|
|||||||
|
|
||||||
|
|
||||||
bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
||||||
|
QList<uint64_t>& target = config.m_ifname.isEmpty()
|
||||||
|
? m_globalRules
|
||||||
|
: m_tunnelRules[config.m_ifname];
|
||||||
|
|
||||||
// Start the firewall transaction
|
// Start the firewall transaction
|
||||||
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
|
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
|
||||||
if (result != ERROR_SUCCESS) {
|
if (result != ERROR_SUCCESS) {
|
||||||
@@ -288,12 +305,12 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
|||||||
logger.info() << "Enabling traffic for peer"
|
logger.info() << "Enabling traffic for peer"
|
||||||
<< config.m_serverPublicKey;
|
<< config.m_serverPublicKey;
|
||||||
if (!blockTrafficTo(config.m_allowedIPAddressRanges, LOW_WEIGHT,
|
if (!blockTrafficTo(config.m_allowedIPAddressRanges, LOW_WEIGHT,
|
||||||
"Block Internet", config.m_serverPublicKey)) {
|
"Block Internet", target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!config.m_primaryDnsServer.isEmpty()) {
|
if (!config.m_primaryDnsServer.isEmpty()) {
|
||||||
if (!allowTrafficTo(QHostAddress(config.m_primaryDnsServer), 53, HIGH_WEIGHT,
|
if (!allowTrafficTo(QHostAddress(config.m_primaryDnsServer), 53, HIGH_WEIGHT,
|
||||||
"Allow DNS-Server", config.m_serverPublicKey)) {
|
"Allow DNS-Server", target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// In some cases, we might configure a 2nd DNS server for IPv6, however
|
// In some cases, we might configure a 2nd DNS server for IPv6, however
|
||||||
@@ -302,7 +319,7 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
|||||||
if (config.m_primaryDnsServer == config.m_serverIpv4Gateway) {
|
if (config.m_primaryDnsServer == config.m_serverIpv4Gateway) {
|
||||||
if (!allowTrafficTo(QHostAddress(config.m_serverIpv6Gateway), 53,
|
if (!allowTrafficTo(QHostAddress(config.m_serverIpv6Gateway), 53,
|
||||||
HIGH_WEIGHT, "Allow extra IPv6 DNS-Server",
|
HIGH_WEIGHT, "Allow extra IPv6 DNS-Server",
|
||||||
config.m_serverPublicKey)) {
|
target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,7 +327,7 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
|||||||
|
|
||||||
if (!config.m_secondaryDnsServer.isEmpty()) {
|
if (!config.m_secondaryDnsServer.isEmpty()) {
|
||||||
if (!allowTrafficTo(QHostAddress(config.m_secondaryDnsServer), 53, HIGH_WEIGHT,
|
if (!allowTrafficTo(QHostAddress(config.m_secondaryDnsServer), 53, HIGH_WEIGHT,
|
||||||
"Allow DNS-Server", config.m_serverPublicKey)) {
|
"Allow DNS-Server", target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// In some cases, we might configure a 2nd DNS server for IPv6, however
|
// In some cases, we might configure a 2nd DNS server for IPv6, however
|
||||||
@@ -319,7 +336,7 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
|||||||
if (config.m_secondaryDnsServer == config.m_serverIpv4Gateway) {
|
if (config.m_secondaryDnsServer == config.m_serverIpv4Gateway) {
|
||||||
if (!allowTrafficTo(QHostAddress(config.m_serverIpv6Gateway), 53,
|
if (!allowTrafficTo(QHostAddress(config.m_serverIpv6Gateway), 53,
|
||||||
HIGH_WEIGHT, "Allow extra IPv6 DNS-Server",
|
HIGH_WEIGHT, "Allow extra IPv6 DNS-Server",
|
||||||
config.m_serverPublicKey)) {
|
target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,7 +345,7 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
|||||||
for (const QString& dns : config.m_allowedDnsServers) {
|
for (const QString& dns : config.m_allowedDnsServers) {
|
||||||
logger.debug() << "Allow DNS: " << dns;
|
logger.debug() << "Allow DNS: " << dns;
|
||||||
if (!allowTrafficTo(QHostAddress(dns), 53, HIGH_WEIGHT,
|
if (!allowTrafficTo(QHostAddress(dns), 53, HIGH_WEIGHT,
|
||||||
"Allow DNS-Server", config.m_serverPublicKey)) {
|
"Allow DNS-Server", target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -338,7 +355,7 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
|||||||
logger.debug() << "excludedAddresses range: " << i;
|
logger.debug() << "excludedAddresses range: " << i;
|
||||||
|
|
||||||
if (!allowTrafficTo(i, HIGH_WEIGHT,
|
if (!allowTrafficTo(i, HIGH_WEIGHT,
|
||||||
"Allow Ecxlude route", config.m_serverPublicKey)) {
|
"Allow Ecxlude route", target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,35 +371,6 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WindowsFirewall::disablePeerTraffic(const QString& pubkey) {
|
|
||||||
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
|
|
||||||
auto cleanup = qScopeGuard([&] {
|
|
||||||
if (result != ERROR_SUCCESS) {
|
|
||||||
FwpmTransactionAbort0(m_sessionHandle);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (result != ERROR_SUCCESS) {
|
|
||||||
logger.error() << "FwpmTransactionBegin0 failed. Return value:.\n"
|
|
||||||
<< result;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info() << "Disabling traffic for peer" << pubkey;
|
|
||||||
for (const auto& filterID : m_peerRules.values(pubkey)) {
|
|
||||||
FwpmFilterDeleteById0(m_sessionHandle, filterID);
|
|
||||||
m_peerRules.remove(pubkey, filterID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commit!
|
|
||||||
result = FwpmTransactionCommit0(m_sessionHandle);
|
|
||||||
if (result != ERROR_SUCCESS) {
|
|
||||||
logger.error() << "FwpmTransactionCommit0 failed. Return value:.\n"
|
|
||||||
<< result;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WindowsFirewall::disableKillSwitch() {
|
bool WindowsFirewall::disableKillSwitch() {
|
||||||
return KillSwitch::instance()->disableKillSwitch();
|
return KillSwitch::instance()->disableKillSwitch();
|
||||||
}
|
}
|
||||||
@@ -400,11 +388,13 @@ bool WindowsFirewall::allowAllTraffic() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& filterID : m_peerRules.values()) {
|
for (const auto& bucket : qAsConst(m_tunnelRules)) {
|
||||||
|
for (const auto& filterID : bucket) {
|
||||||
FwpmFilterDeleteById0(m_sessionHandle, filterID);
|
FwpmFilterDeleteById0(m_sessionHandle, filterID);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& filterID : qAsConst(m_activeRules)) {
|
for (const auto& filterID : qAsConst(m_globalRules)) {
|
||||||
FwpmFilterDeleteById0(m_sessionHandle, filterID);
|
FwpmFilterDeleteById0(m_sessionHandle, filterID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,15 +405,42 @@ bool WindowsFirewall::allowAllTraffic() {
|
|||||||
<< result;
|
<< result;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_peerRules.clear();
|
m_tunnelRules.clear();
|
||||||
m_activeRules.clear();
|
m_globalRules.clear();
|
||||||
logger.debug() << "Firewall Disabled!";
|
logger.debug() << "Firewall Disabled!";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WindowsFirewall::disableKillSwitchForTunnel(const QString& ifname) {
|
||||||
|
if (ifname.isEmpty() || !m_tunnelRules.contains(ifname)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
|
||||||
|
if (result != ERROR_SUCCESS) {
|
||||||
|
logger.error() << "FwpmTransactionBegin0 failed. Return value:" << result;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QList<uint64_t> filters = m_tunnelRules.take(ifname);
|
||||||
|
logger.info() << "Disabling killswitch filters for tunnel" << ifname
|
||||||
|
<< "count:" << filters.length();
|
||||||
|
for (const auto& filterID : filters) {
|
||||||
|
FwpmFilterDeleteById0(m_sessionHandle, filterID);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = FwpmTransactionCommit0(m_sessionHandle);
|
||||||
|
if (result != ERROR_SUCCESS) {
|
||||||
|
logger.error() << "FwpmTransactionCommit0 failed. Return value:" << result;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool WindowsFirewall::allowTrafficForAppOnAll(const QString& exePath,
|
bool WindowsFirewall::allowTrafficForAppOnAll(const QString& exePath,
|
||||||
int weight,
|
int weight,
|
||||||
const QString& title) {
|
const QString& title,
|
||||||
|
QList<uint64_t>& target) {
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result = ERROR_SUCCESS;
|
||||||
Q_ASSERT(weight <= 15);
|
Q_ASSERT(weight <= 15);
|
||||||
|
|
||||||
@@ -460,7 +477,7 @@ bool WindowsFirewall::allowTrafficForAppOnAll(const QString& exePath,
|
|||||||
{
|
{
|
||||||
QString desc("Permit (out) IPv4 Traffic of: " + appName);
|
QString desc("Permit (out) IPv4 Traffic of: " + appName);
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
|
||||||
if (!enableFilter(&filter, title, desc)) {
|
if (!enableFilter(&filter, title, desc, target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -468,7 +485,7 @@ bool WindowsFirewall::allowTrafficForAppOnAll(const QString& exePath,
|
|||||||
{
|
{
|
||||||
QString desc("Permit (in) IPv4 Traffic of: " + appName);
|
QString desc("Permit (in) IPv4 Traffic of: " + appName);
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
|
||||||
if (!enableFilter(&filter, title, desc)) {
|
if (!enableFilter(&filter, title, desc, target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -476,7 +493,8 @@ bool WindowsFirewall::allowTrafficForAppOnAll(const QString& exePath,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WindowsFirewall::allowTrafficOfAdapter(int networkAdapter, uint8_t weight,
|
bool WindowsFirewall::allowTrafficOfAdapter(int networkAdapter, uint8_t weight,
|
||||||
const QString& title) {
|
const QString& title,
|
||||||
|
QList<uint64_t>& target) {
|
||||||
FWPM_FILTER_CONDITION0 conds;
|
FWPM_FILTER_CONDITION0 conds;
|
||||||
// Condition: Request must be targeting the TUN interface
|
// Condition: Request must be targeting the TUN interface
|
||||||
conds.fieldKey = FWPM_CONDITION_INTERFACE_INDEX;
|
conds.fieldKey = FWPM_CONDITION_INTERFACE_INDEX;
|
||||||
@@ -498,25 +516,25 @@ bool WindowsFirewall::allowTrafficOfAdapter(int networkAdapter, uint8_t weight,
|
|||||||
// #1 Permit outbound IPv4 traffic.
|
// #1 Permit outbound IPv4 traffic.
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
|
||||||
if (!enableFilter(&filter, title,
|
if (!enableFilter(&filter, title,
|
||||||
description.arg("out").arg(networkAdapter))) {
|
description.arg("out").arg(networkAdapter), target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// #2 Permit inbound IPv4 traffic.
|
// #2 Permit inbound IPv4 traffic.
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
|
||||||
if (!enableFilter(&filter, title,
|
if (!enableFilter(&filter, title,
|
||||||
description.arg("in").arg(networkAdapter))) {
|
description.arg("in").arg(networkAdapter), target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// #3 Permit outbound IPv6 traffic.
|
// #3 Permit outbound IPv6 traffic.
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
|
||||||
if (!enableFilter(&filter, title,
|
if (!enableFilter(&filter, title,
|
||||||
description.arg("out").arg(networkAdapter))) {
|
description.arg("out").arg(networkAdapter), target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// #4 Permit inbound IPv6 traffic.
|
// #4 Permit inbound IPv6 traffic.
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6;
|
||||||
if (!enableFilter(&filter, title,
|
if (!enableFilter(&filter, title,
|
||||||
description.arg("in").arg(networkAdapter))) {
|
description.arg("in").arg(networkAdapter), target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -524,7 +542,7 @@ bool WindowsFirewall::allowTrafficOfAdapter(int networkAdapter, uint8_t weight,
|
|||||||
|
|
||||||
bool WindowsFirewall::allowTrafficTo(const IPAddress& addr, int weight,
|
bool WindowsFirewall::allowTrafficTo(const IPAddress& addr, int weight,
|
||||||
const QString& title,
|
const QString& title,
|
||||||
const QString& peer) {
|
QList<uint64_t>& target) {
|
||||||
GUID layerKeyOut;
|
GUID layerKeyOut;
|
||||||
GUID layerKeyIn;
|
GUID layerKeyIn;
|
||||||
if (addr.type() == QAbstractSocket::IPv4Protocol) {
|
if (addr.type() == QAbstractSocket::IPv4Protocol) {
|
||||||
@@ -562,11 +580,11 @@ bool WindowsFirewall::allowTrafficTo(const IPAddress& addr, int weight,
|
|||||||
// Send the filters down to the firewall.
|
// Send the filters down to the firewall.
|
||||||
QString description = "Permit traffic %1 " + addr.toString();
|
QString description = "Permit traffic %1 " + addr.toString();
|
||||||
filter.layerKey = layerKeyOut;
|
filter.layerKey = layerKeyOut;
|
||||||
if (!enableFilter(&filter, title, description.arg("to"), peer)) {
|
if (!enableFilter(&filter, title, description.arg("to"), target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
filter.layerKey = layerKeyIn;
|
filter.layerKey = layerKeyIn;
|
||||||
if (!enableFilter(&filter, title, description.arg("from"), peer)) {
|
if (!enableFilter(&filter, title, description.arg("from"), target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -574,7 +592,7 @@ bool WindowsFirewall::allowTrafficTo(const IPAddress& addr, int weight,
|
|||||||
|
|
||||||
bool WindowsFirewall::allowTrafficTo(const QHostAddress& targetIP, uint port,
|
bool WindowsFirewall::allowTrafficTo(const QHostAddress& targetIP, uint port,
|
||||||
int weight, const QString& title,
|
int weight, const QString& title,
|
||||||
const QString& peer) {
|
QList<uint64_t>& target) {
|
||||||
bool isIPv4 = targetIP.protocol() == QAbstractSocket::IPv4Protocol;
|
bool isIPv4 = targetIP.protocol() == QAbstractSocket::IPv4Protocol;
|
||||||
GUID layerOut =
|
GUID layerOut =
|
||||||
isIPv4 ? FWPM_LAYER_ALE_AUTH_CONNECT_V4 : FWPM_LAYER_ALE_AUTH_CONNECT_V6;
|
isIPv4 ? FWPM_LAYER_ALE_AUTH_CONNECT_V4 : FWPM_LAYER_ALE_AUTH_CONNECT_V6;
|
||||||
@@ -623,19 +641,20 @@ bool WindowsFirewall::allowTrafficTo(const QHostAddress& targetIP, uint port,
|
|||||||
filter.layerKey = layerOut;
|
filter.layerKey = layerOut;
|
||||||
if (!enableFilter(&filter, title,
|
if (!enableFilter(&filter, title,
|
||||||
description.arg("to").arg(targetIP.toString()).arg(port),
|
description.arg("to").arg(targetIP.toString()).arg(port),
|
||||||
peer)) {
|
target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
filter.layerKey = layerIn;
|
filter.layerKey = layerIn;
|
||||||
if (!enableFilter(&filter, title,
|
if (!enableFilter(&filter, title,
|
||||||
description.arg("from").arg(targetIP.toString()).arg(port),
|
description.arg("from").arg(targetIP.toString()).arg(port),
|
||||||
peer)) {
|
target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WindowsFirewall::allowDHCPTraffic(uint8_t weight, const QString& title) {
|
bool WindowsFirewall::allowDHCPTraffic(uint8_t weight, const QString& title,
|
||||||
|
QList<uint64_t>& target) {
|
||||||
// Allow outbound DHCPv4
|
// Allow outbound DHCPv4
|
||||||
{
|
{
|
||||||
FWPM_FILTER_CONDITION0 conds[4];
|
FWPM_FILTER_CONDITION0 conds[4];
|
||||||
@@ -672,7 +691,7 @@ bool WindowsFirewall::allowDHCPTraffic(uint8_t weight, const QString& title) {
|
|||||||
|
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
|
||||||
|
|
||||||
if (!enableFilter(&filter, title, "Allow Outbound DHCP")) {
|
if (!enableFilter(&filter, title, "Allow Outbound DHCP", target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -705,7 +724,7 @@ bool WindowsFirewall::allowDHCPTraffic(uint8_t weight, const QString& title) {
|
|||||||
filter.subLayerKey = ST_FW_WINFW_BASELINE_SUBLAYER_KEY;
|
filter.subLayerKey = ST_FW_WINFW_BASELINE_SUBLAYER_KEY;
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
|
||||||
|
|
||||||
if (!enableFilter(&filter, title, "Allow inbound DHCP")) {
|
if (!enableFilter(&filter, title, "Allow inbound DHCP", target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -740,7 +759,7 @@ bool WindowsFirewall::allowDHCPTraffic(uint8_t weight, const QString& title) {
|
|||||||
filter.subLayerKey = ST_FW_WINFW_BASELINE_SUBLAYER_KEY;
|
filter.subLayerKey = ST_FW_WINFW_BASELINE_SUBLAYER_KEY;
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
|
||||||
|
|
||||||
if (!enableFilter(&filter, title, "Allow outbound DHCPv6")) {
|
if (!enableFilter(&filter, title, "Allow outbound DHCPv6", target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -773,7 +792,7 @@ bool WindowsFirewall::allowDHCPTraffic(uint8_t weight, const QString& title) {
|
|||||||
filter.weight.uint8 = weight;
|
filter.weight.uint8 = weight;
|
||||||
filter.subLayerKey = ST_FW_WINFW_BASELINE_SUBLAYER_KEY;
|
filter.subLayerKey = ST_FW_WINFW_BASELINE_SUBLAYER_KEY;
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6;
|
||||||
if (!enableFilter(&filter, title, "Allow inbound DHCPv6")) {
|
if (!enableFilter(&filter, title, "Allow inbound DHCPv6", target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -781,7 +800,8 @@ bool WindowsFirewall::allowDHCPTraffic(uint8_t weight, const QString& title) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allows the internal Hyper-V Switches to work.
|
// Allows the internal Hyper-V Switches to work.
|
||||||
bool WindowsFirewall::allowHyperVTraffic(uint8_t weight, const QString& title) {
|
bool WindowsFirewall::allowHyperVTraffic(uint8_t weight, const QString& title,
|
||||||
|
QList<uint64_t>& target) {
|
||||||
FWPM_FILTER_CONDITION0 cond;
|
FWPM_FILTER_CONDITION0 cond;
|
||||||
// Condition: Request must be targeting the TUN interface
|
// Condition: Request must be targeting the TUN interface
|
||||||
cond.fieldKey = FWPM_CONDITION_L2_FLAGS;
|
cond.fieldKey = FWPM_CONDITION_L2_FLAGS;
|
||||||
@@ -801,12 +821,12 @@ bool WindowsFirewall::allowHyperVTraffic(uint8_t weight, const QString& title) {
|
|||||||
|
|
||||||
// #1 Permit Hyper-V => Hyper-V outbound.
|
// #1 Permit Hyper-V => Hyper-V outbound.
|
||||||
filter.layerKey = FWPM_LAYER_OUTBOUND_MAC_FRAME_NATIVE;
|
filter.layerKey = FWPM_LAYER_OUTBOUND_MAC_FRAME_NATIVE;
|
||||||
if (!enableFilter(&filter, title, "Permit Hyper-V => Hyper-V outbound")) {
|
if (!enableFilter(&filter, title, "Permit Hyper-V => Hyper-V outbound", target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// #2 Permit Hyper-V => Hyper-V inbound.
|
// #2 Permit Hyper-V => Hyper-V inbound.
|
||||||
filter.layerKey = FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE;
|
filter.layerKey = FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE;
|
||||||
if (!enableFilter(&filter, title, "Permit Hyper-V => Hyper-V inbound")) {
|
if (!enableFilter(&filter, title, "Permit Hyper-V => Hyper-V inbound", target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -814,7 +834,7 @@ bool WindowsFirewall::allowHyperVTraffic(uint8_t weight, const QString& title) {
|
|||||||
|
|
||||||
bool WindowsFirewall::blockTrafficTo(const IPAddress& addr, uint8_t weight,
|
bool WindowsFirewall::blockTrafficTo(const IPAddress& addr, uint8_t weight,
|
||||||
const QString& title,
|
const QString& title,
|
||||||
const QString& peer) {
|
QList<uint64_t>& target) {
|
||||||
QString description("Block traffic %1 %2 ");
|
QString description("Block traffic %1 %2 ");
|
||||||
|
|
||||||
auto lower = addr.address();
|
auto lower = addr.address();
|
||||||
@@ -852,12 +872,12 @@ bool WindowsFirewall::blockTrafficTo(const IPAddress& addr, uint8_t weight,
|
|||||||
|
|
||||||
filter.layerKey = layerKeyOut;
|
filter.layerKey = layerKeyOut;
|
||||||
if (!enableFilter(&filter, title, description.arg("to").arg(addr.toString()),
|
if (!enableFilter(&filter, title, description.arg("to").arg(addr.toString()),
|
||||||
peer)) {
|
target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
filter.layerKey = layerKeyIn;
|
filter.layerKey = layerKeyIn;
|
||||||
if (!enableFilter(&filter, title,
|
if (!enableFilter(&filter, title,
|
||||||
description.arg("from").arg(addr.toString()), peer)) {
|
description.arg("from").arg(addr.toString()), target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -865,9 +885,9 @@ bool WindowsFirewall::blockTrafficTo(const IPAddress& addr, uint8_t weight,
|
|||||||
|
|
||||||
bool WindowsFirewall::blockTrafficTo(const QList<IPAddress>& rangeList,
|
bool WindowsFirewall::blockTrafficTo(const QList<IPAddress>& rangeList,
|
||||||
uint8_t weight, const QString& title,
|
uint8_t weight, const QString& title,
|
||||||
const QString& peer) {
|
QList<uint64_t>& target) {
|
||||||
for (auto range : rangeList) {
|
for (auto range : rangeList) {
|
||||||
if (!blockTrafficTo(range, weight, title, peer)) {
|
if (!blockTrafficTo(range, weight, title, target)) {
|
||||||
logger.info() << "Setting Range of" << range.toString() << "failed";
|
logger.info() << "Setting Range of" << range.toString() << "failed";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -923,7 +943,8 @@ void WindowsFirewall::importAddress(const QHostAddress& addr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WindowsFirewall::blockTrafficOnPort(uint port, uint8_t weight,
|
bool WindowsFirewall::blockTrafficOnPort(uint port, uint8_t weight,
|
||||||
const QString& title) {
|
const QString& title,
|
||||||
|
QList<uint64_t>& target) {
|
||||||
// Allow Traffic to IP with PORT using any protocol
|
// Allow Traffic to IP with PORT using any protocol
|
||||||
FWPM_FILTER_CONDITION0 conds[3];
|
FWPM_FILTER_CONDITION0 conds[3];
|
||||||
conds[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL;
|
conds[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL;
|
||||||
@@ -953,20 +974,20 @@ bool WindowsFirewall::blockTrafficOnPort(uint port, uint8_t weight,
|
|||||||
|
|
||||||
QString description("Block %1 on Port %2");
|
QString description("Block %1 on Port %2");
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
|
||||||
if (!enableFilter(&filter, title, description.arg("outgoing v6").arg(port))) {
|
if (!enableFilter(&filter, title, description.arg("outgoing v6").arg(port), target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
|
||||||
if (!enableFilter(&filter, title, description.arg("outgoing v4").arg(port))) {
|
if (!enableFilter(&filter, title, description.arg("outgoing v4").arg(port), target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
|
||||||
if (!enableFilter(&filter, title, description.arg("incoming v4").arg(port))) {
|
if (!enableFilter(&filter, title, description.arg("incoming v4").arg(port), target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6;
|
filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6;
|
||||||
if (!enableFilter(&filter, title, description.arg("incoming v6").arg(port))) {
|
if (!enableFilter(&filter, title, description.arg("incoming v6").arg(port), target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -974,7 +995,7 @@ bool WindowsFirewall::blockTrafficOnPort(uint port, uint8_t weight,
|
|||||||
|
|
||||||
bool WindowsFirewall::enableFilter(FWPM_FILTER0* filter, const QString& title,
|
bool WindowsFirewall::enableFilter(FWPM_FILTER0* filter, const QString& title,
|
||||||
const QString& description,
|
const QString& description,
|
||||||
const QString& peer) {
|
QList<uint64_t>& target) {
|
||||||
uint64_t filterID = 0;
|
uint64_t filterID = 0;
|
||||||
auto name = title.toStdWString();
|
auto name = title.toStdWString();
|
||||||
auto desc = description.toStdWString();
|
auto desc = description.toStdWString();
|
||||||
@@ -987,16 +1008,12 @@ bool WindowsFirewall::enableFilter(FWPM_FILTER0* filter, const QString& title,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
logger.info() << "Filter added: " << title << ":" << description;
|
logger.info() << "Filter added: " << title << ":" << description;
|
||||||
if (peer.isEmpty()) {
|
target.append(filterID);
|
||||||
m_activeRules.append(filterID);
|
|
||||||
} else {
|
|
||||||
m_peerRules.insert(peer, filterID);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WindowsFirewall::allowLoopbackTraffic(uint8_t weight,
|
bool WindowsFirewall::allowLoopbackTraffic(uint8_t weight, const QString& title,
|
||||||
const QString& title) {
|
QList<uint64_t>& target) {
|
||||||
QList<QNetworkInterface> networkInterfaces =
|
QList<QNetworkInterface> networkInterfaces =
|
||||||
QNetworkInterface::allInterfaces();
|
QNetworkInterface::allInterfaces();
|
||||||
for (const auto& iface : networkInterfaces) {
|
for (const auto& iface : networkInterfaces) {
|
||||||
@@ -1004,7 +1021,7 @@ bool WindowsFirewall::allowLoopbackTraffic(uint8_t weight,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!allowTrafficOfAdapter(iface.index(), weight,
|
if (!allowTrafficOfAdapter(iface.index(), weight,
|
||||||
title.arg(iface.name()))) {
|
title.arg(iface.name()), target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
|
#include <QMap>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
@@ -38,38 +39,42 @@ class WindowsFirewall final : public QObject {
|
|||||||
static WindowsFirewall* create(QObject* parent);
|
static WindowsFirewall* create(QObject* parent);
|
||||||
~WindowsFirewall() override;
|
~WindowsFirewall() override;
|
||||||
|
|
||||||
bool enableInterface(int vpnAdapterIndex);
|
bool enableInterface(int vpnAdapterIndex, const QString& ifname = QString());
|
||||||
bool enableLanBypass(const QList<IPAddress>& ranges);
|
bool enableLanBypass(const QList<IPAddress>& ranges);
|
||||||
bool enablePeerTraffic(const InterfaceConfig& config);
|
bool enablePeerTraffic(const InterfaceConfig& config);
|
||||||
bool disablePeerTraffic(const QString& pubkey);
|
|
||||||
bool disableKillSwitch();
|
bool disableKillSwitch();
|
||||||
|
bool disableKillSwitchForTunnel(const QString& ifname);
|
||||||
bool allowAllTraffic();
|
bool allowAllTraffic();
|
||||||
bool allowTrafficRange(const QStringList& ranges);
|
bool allowTrafficRange(const QStringList& ranges, const QString& ifname = QString());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool initSublayer();
|
static bool initSublayer();
|
||||||
WindowsFirewall(HANDLE session, QObject* parent);
|
WindowsFirewall(HANDLE session, QObject* parent);
|
||||||
HANDLE m_sessionHandle;
|
HANDLE m_sessionHandle;
|
||||||
bool m_init = false;
|
bool m_init = false;
|
||||||
QList<uint64_t> m_activeRules;
|
QList<uint64_t> m_globalRules;
|
||||||
QMultiMap<QString, uint64_t> m_peerRules;
|
QMap<QString, QList<uint64_t>> m_tunnelRules;
|
||||||
|
|
||||||
bool allowTrafficForAppOnAll(const QString& exePath, int weight,
|
bool allowTrafficForAppOnAll(const QString& exePath, int weight,
|
||||||
const QString& title);
|
const QString& title, QList<uint64_t>& target);
|
||||||
bool blockTrafficTo(const QList<IPAddress>& range, uint8_t weight,
|
bool blockTrafficTo(const QList<IPAddress>& range, uint8_t weight,
|
||||||
const QString& title, const QString& peer = QString());
|
const QString& title, QList<uint64_t>& target);
|
||||||
bool blockTrafficTo(const IPAddress& addr, uint8_t weight,
|
bool blockTrafficTo(const IPAddress& addr, uint8_t weight,
|
||||||
const QString& title, const QString& peer = QString());
|
const QString& title, QList<uint64_t>& target);
|
||||||
bool blockTrafficOnPort(uint port, uint8_t weight, const QString& title);
|
bool blockTrafficOnPort(uint port, uint8_t weight, const QString& title,
|
||||||
|
QList<uint64_t>& target);
|
||||||
bool allowTrafficTo(const IPAddress& addr, int weight, const QString& title,
|
bool allowTrafficTo(const IPAddress& addr, int weight, const QString& title,
|
||||||
const QString& peer = QString());
|
QList<uint64_t>& target);
|
||||||
bool allowTrafficTo(const QHostAddress& targetIP, uint port, int weight,
|
bool allowTrafficTo(const QHostAddress& targetIP, uint port, int weight,
|
||||||
const QString& title, const QString& peer = QString());
|
const QString& title, QList<uint64_t>& target);
|
||||||
bool allowTrafficOfAdapter(int networkAdapter, uint8_t weight,
|
bool allowTrafficOfAdapter(int networkAdapter, uint8_t weight,
|
||||||
const QString& title);
|
const QString& title, QList<uint64_t>& target);
|
||||||
bool allowDHCPTraffic(uint8_t weight, const QString& title);
|
bool allowDHCPTraffic(uint8_t weight, const QString& title,
|
||||||
bool allowHyperVTraffic(uint8_t weight, const QString& title);
|
QList<uint64_t>& target);
|
||||||
bool allowLoopbackTraffic(uint8_t weight, const QString& title);
|
bool allowHyperVTraffic(uint8_t weight, const QString& title,
|
||||||
|
QList<uint64_t>& target);
|
||||||
|
bool allowLoopbackTraffic(uint8_t weight, const QString& title,
|
||||||
|
QList<uint64_t>& target);
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
QString getCurrentPath();
|
QString getCurrentPath();
|
||||||
@@ -78,8 +83,7 @@ class WindowsFirewall final : public QObject {
|
|||||||
void importAddress(const QHostAddress& addr, OUT FWP_CONDITION_VALUE0_& value,
|
void importAddress(const QHostAddress& addr, OUT FWP_CONDITION_VALUE0_& value,
|
||||||
OUT QByteArray* v6DataBuffer);
|
OUT QByteArray* v6DataBuffer);
|
||||||
bool enableFilter(FWPM_FILTER0* filter, const QString& title,
|
bool enableFilter(FWPM_FILTER0* filter, const QString& title,
|
||||||
const QString& description,
|
const QString& description, QList<uint64_t>& target);
|
||||||
const QString& peer = QString());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WINDOWSFIREWALL_H
|
#endif // WINDOWSFIREWALL_H
|
||||||
|
|||||||
+33
-17
@@ -166,20 +166,37 @@ void VpnConnection::connectToVpn(const QString &serverId, DockerContainer contai
|
|||||||
NetworkUtilities::getIPAddress(vpnConfiguration.value(configKey::hostName).toString());
|
NetworkUtilities::getIPAddress(vpnConfiguration.value(configKey::hostName).toString());
|
||||||
|
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
// Seamless WG -> WG switch path: already connected via Tunnel, new container is also WG.
|
const bool isWg = VpnProtocol::isWireGuardBased(container);
|
||||||
if (m_active
|
const QString preAllocatedIfname = isWg ? allocateIfname() : QString();
|
||||||
|
|
||||||
|
bool seamlessSwitch = m_active
|
||||||
&& m_connectionState == Vpn::ConnectionState::Connected
|
&& m_connectionState == Vpn::ConnectionState::Connected
|
||||||
&& VpnProtocol::isWireGuardBased(container)) {
|
&& isWg;
|
||||||
if (!m_trafficGuard->allowEndpoint(resolvedRemote)) {
|
#ifdef Q_OS_WIN
|
||||||
|
if (seamlessSwitch) {
|
||||||
|
auto clientIpFor = [](const QJsonObject& cfg) {
|
||||||
|
const QString proto = cfg.value("protocol").toString();
|
||||||
|
return cfg.value(proto + "_config_data").toObject().value(configKey::clientIp).toString();
|
||||||
|
};
|
||||||
|
if (clientIpFor(vpnConfiguration) == clientIpFor(m_active->config())) {
|
||||||
|
seamlessSwitch = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (seamlessSwitch) {
|
||||||
|
if (!m_trafficGuard->allowEndpoint(resolvedRemote, preAllocatedIfname)) {
|
||||||
|
releaseIfname(preAllocatedIfname);
|
||||||
setConnectionState(Vpn::ConnectionState::Error);
|
setConnectionState(Vpn::ConnectionState::Error);
|
||||||
emit vpnProtocolError(ErrorCode::AmneziaServiceConnectionFailed);
|
emit vpnProtocolError(ErrorCode::AmneziaServiceConnectionFailed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
startTunnelSwitch(container, vpnConfiguration, resolvedRemote);
|
startTunnelSwitch(container, vpnConfiguration, resolvedRemote, preAllocatedIfname);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_trafficGuard->allowEndpoint(resolvedRemote)) {
|
if (!m_trafficGuard->allowEndpoint(resolvedRemote, preAllocatedIfname)) {
|
||||||
|
if (isWg) releaseIfname(preAllocatedIfname);
|
||||||
setConnectionState(Vpn::ConnectionState::Error);
|
setConnectionState(Vpn::ConnectionState::Error);
|
||||||
emit vpnProtocolError(ErrorCode::AmneziaServiceConnectionFailed);
|
emit vpnProtocolError(ErrorCode::AmneziaServiceConnectionFailed);
|
||||||
return;
|
return;
|
||||||
@@ -212,10 +229,9 @@ void VpnConnection::connectToVpn(const QString &serverId, DockerContainer contai
|
|||||||
m_remoteAddress = resolvedRemote;
|
m_remoteAddress = resolvedRemote;
|
||||||
|
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
if (VpnProtocol::isWireGuardBased(container)) {
|
if (isWg) {
|
||||||
const QString ifname = allocateIfname();
|
config.insert("ifname", preAllocatedIfname);
|
||||||
config.insert("ifname", ifname);
|
m_active = new Tunnel(preAllocatedIfname, container, config, resolvedRemote, this);
|
||||||
m_active = new Tunnel(ifname, container, config, resolvedRemote, this);
|
|
||||||
wireTunnelSignals(m_active, /*isActive=*/true);
|
wireTunnelSignals(m_active, /*isActive=*/true);
|
||||||
wireDaemonReconnectSignals();
|
wireDaemonReconnectSignals();
|
||||||
m_trafficGuard->setConfig(config);
|
m_trafficGuard->setConfig(config);
|
||||||
@@ -255,7 +271,10 @@ void VpnConnection::createProtocolConnections()
|
|||||||
connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
|
connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
|
||||||
connect(m_vpnProtocol.data(), &VpnProtocol::connectionStateChanged, this, &VpnConnection::setConnectionState);
|
connect(m_vpnProtocol.data(), &VpnProtocol::connectionStateChanged, this, &VpnConnection::setConnectionState);
|
||||||
connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64)));
|
connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64)));
|
||||||
connect(m_vpnProtocol.data(), &VpnProtocol::tunnelAddressesUpdated, m_trafficGuard.data(), &VpnTrafficGuard::applyFirewall);
|
connect(m_vpnProtocol.data(), &VpnProtocol::tunnelAddressesUpdated, this,
|
||||||
|
[this](const QString& gateway, const QString& localAddress) {
|
||||||
|
m_trafficGuard->applyKillSwitch(nullptr, gateway, localAddress);
|
||||||
|
});
|
||||||
|
|
||||||
wireDaemonReconnectSignals();
|
wireDaemonReconnectSignals();
|
||||||
}
|
}
|
||||||
@@ -532,13 +551,14 @@ void VpnConnection::setConnectionState(Vpn::ConnectionState state) {
|
|||||||
|
|
||||||
void VpnConnection::startTunnelSwitch(DockerContainer container,
|
void VpnConnection::startTunnelSwitch(DockerContainer container,
|
||||||
const QJsonObject &vpnConfiguration,
|
const QJsonObject &vpnConfiguration,
|
||||||
const QString &resolvedRemote)
|
const QString &resolvedRemote,
|
||||||
|
const QString &stagingIfname)
|
||||||
{
|
{
|
||||||
QJsonObject config = vpnConfiguration;
|
QJsonObject config = vpnConfiguration;
|
||||||
|
config.insert("ifname", stagingIfname);
|
||||||
appendKillSwitchConfig(config);
|
appendKillSwitchConfig(config);
|
||||||
appendSplitTunnelingConfig(config);
|
appendSplitTunnelingConfig(config);
|
||||||
|
|
||||||
const QString stagingIfname = allocateIfname();
|
|
||||||
m_staging = new Tunnel(stagingIfname, container, config, resolvedRemote, this);
|
m_staging = new Tunnel(stagingIfname, container, config, resolvedRemote, this);
|
||||||
wireTunnelSignals(m_staging, /*isActive=*/false);
|
wireTunnelSignals(m_staging, /*isActive=*/false);
|
||||||
|
|
||||||
@@ -576,10 +596,6 @@ void VpnConnection::onTunnelActivated()
|
|||||||
|
|
||||||
if (tunnel == m_active) {
|
if (tunnel == m_active) {
|
||||||
setConnectionState(Vpn::ConnectionState::Connected);
|
setConnectionState(Vpn::ConnectionState::Connected);
|
||||||
if (auto proto = m_active->protocol()) {
|
|
||||||
m_trafficGuard->applyFirewall(proto->vpnGateway(),
|
|
||||||
proto->vpnLocalAddress());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,8 @@ private:
|
|||||||
|
|
||||||
void startTunnelSwitch(DockerContainer container,
|
void startTunnelSwitch(DockerContainer container,
|
||||||
const QJsonObject &vpnConfiguration,
|
const QJsonObject &vpnConfiguration,
|
||||||
const QString &resolvedRemote);
|
const QString &resolvedRemote,
|
||||||
|
const QString &stagingIfname);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onTunnelPrepared();
|
void onTunnelPrepared();
|
||||||
|
|||||||
@@ -35,9 +35,10 @@ class IpcInterface
|
|||||||
SLOT( bool StopRoutingIpv6() );
|
SLOT( bool StopRoutingIpv6() );
|
||||||
|
|
||||||
SLOT( bool disableKillSwitch() );
|
SLOT( bool disableKillSwitch() );
|
||||||
|
SLOT( bool disableKillSwitchForTunnel( const QString &ifname, const QStringList &remainingRanges ) );
|
||||||
SLOT( bool disableAllTraffic() );
|
SLOT( bool disableAllTraffic() );
|
||||||
SLOT( bool refreshKillSwitch( bool enabled ) );
|
SLOT( bool refreshKillSwitch( bool enabled ) );
|
||||||
SLOT( bool addKillSwitchAllowedRange( const QStringList ranges ) );
|
SLOT( bool addKillSwitchAllowedRange( const QString &ifname, const QStringList ranges ) );
|
||||||
SLOT( bool resetKillSwitchAllowedRange( const QStringList ranges ) );
|
SLOT( bool resetKillSwitchAllowedRange( const QStringList ranges ) );
|
||||||
SLOT( bool enablePeerTraffic( const QJsonObject &configStr) );
|
SLOT( bool enablePeerTraffic( const QJsonObject &configStr) );
|
||||||
SLOT( bool enableKillSwitch( const QJsonObject &excludeAddr, int vpnAdapterIndex) );
|
SLOT( bool enableKillSwitch( const QJsonObject &excludeAddr, int vpnAdapterIndex) );
|
||||||
|
|||||||
+12
-3
@@ -282,13 +282,13 @@ bool IpcServer::resetKillSwitchAllowedRange(QStringList ranges)
|
|||||||
return KillSwitch::instance()->resetAllowedRange(ranges);
|
return KillSwitch::instance()->resetAllowedRange(ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IpcServer::addKillSwitchAllowedRange(QStringList ranges)
|
bool IpcServer::addKillSwitchAllowedRange(const QString &ifname, QStringList ranges)
|
||||||
{
|
{
|
||||||
#ifdef MZ_DEBUG
|
#ifdef MZ_DEBUG
|
||||||
qDebug() << "IpcServer::addKillSwitchAllowedRange";
|
qDebug() << "IpcServer::addKillSwitchAllowedRange" << ifname;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return KillSwitch::instance()->addAllowedRange(ranges);
|
return KillSwitch::instance()->addAllowedRange(ifname, ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IpcServer::disableAllTraffic()
|
bool IpcServer::disableAllTraffic()
|
||||||
@@ -318,6 +318,15 @@ bool IpcServer::disableKillSwitch()
|
|||||||
return KillSwitch::instance()->disableKillSwitch();
|
return KillSwitch::instance()->disableKillSwitch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IpcServer::disableKillSwitchForTunnel(const QString &ifname, const QStringList &remainingRanges)
|
||||||
|
{
|
||||||
|
#ifdef MZ_DEBUG
|
||||||
|
qDebug() << "IpcServer::disableKillSwitchForTunnel" << ifname;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return KillSwitch::instance()->disableKillSwitchForTunnel(ifname, remainingRanges);
|
||||||
|
}
|
||||||
|
|
||||||
bool IpcServer::enablePeerTraffic(const QJsonObject &configStr)
|
bool IpcServer::enablePeerTraffic(const QJsonObject &configStr)
|
||||||
{
|
{
|
||||||
#ifdef MZ_DEBUG
|
#ifdef MZ_DEBUG
|
||||||
|
|||||||
+2
-1
@@ -41,11 +41,12 @@ public:
|
|||||||
virtual bool StartRoutingIpv6() override;
|
virtual bool StartRoutingIpv6() override;
|
||||||
virtual bool StopRoutingIpv6() override;
|
virtual bool StopRoutingIpv6() override;
|
||||||
virtual bool disableAllTraffic() override;
|
virtual bool disableAllTraffic() override;
|
||||||
virtual bool addKillSwitchAllowedRange(QStringList ranges) override;
|
virtual bool addKillSwitchAllowedRange(const QString &ifname, QStringList ranges) override;
|
||||||
virtual bool resetKillSwitchAllowedRange(QStringList ranges) override;
|
virtual bool resetKillSwitchAllowedRange(QStringList ranges) override;
|
||||||
virtual bool enablePeerTraffic(const QJsonObject &configStr) override;
|
virtual bool enablePeerTraffic(const QJsonObject &configStr) override;
|
||||||
virtual bool enableKillSwitch(const QJsonObject &excludeAddr, int vpnAdapterIndex) override;
|
virtual bool enableKillSwitch(const QJsonObject &excludeAddr, int vpnAdapterIndex) override;
|
||||||
virtual bool disableKillSwitch() override;
|
virtual bool disableKillSwitch() override;
|
||||||
|
virtual bool disableKillSwitchForTunnel(const QString &ifname, const QStringList &remainingRanges) override;
|
||||||
virtual bool refreshKillSwitch( bool enabled ) override;
|
virtual bool refreshKillSwitch( bool enabled ) override;
|
||||||
virtual bool updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers) override;
|
virtual bool updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers) override;
|
||||||
virtual bool restoreResolvers() override;
|
virtual bool restoreResolvers() override;
|
||||||
|
|||||||
@@ -159,6 +159,16 @@ bool KillSwitch::disableKillSwitch() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool KillSwitch::disableKillSwitchForTunnel(const QString& ifname, const QStringList& remainingRanges) {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
Q_UNUSED(remainingRanges)
|
||||||
|
return WindowsFirewall::create(this)->disableKillSwitchForTunnel(ifname);
|
||||||
|
#else
|
||||||
|
Q_UNUSED(ifname)
|
||||||
|
return resetAllowedRange(remainingRanges);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool KillSwitch::disableAllTraffic() {
|
bool KillSwitch::disableAllTraffic() {
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
WindowsFirewall::create(this)->enableInterface(-1);
|
WindowsFirewall::create(this)->enableInterface(-1);
|
||||||
@@ -221,7 +231,15 @@ bool KillSwitch::resetAllowedRange(const QStringList &ranges) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KillSwitch::addAllowedRange(const QStringList &ranges) {
|
bool KillSwitch::addAllowedRange(const QString &ifname, const QStringList &ranges) {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
if (!ifname.isEmpty()) {
|
||||||
|
return WindowsFirewall::create(this)->allowTrafficRange(ranges, ifname);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Q_UNUSED(ifname)
|
||||||
|
#endif
|
||||||
|
|
||||||
for (const QString &range : ranges) {
|
for (const QString &range : ranges) {
|
||||||
if (!range.isEmpty() && !m_allowedRanges.contains(range)) {
|
if (!range.isEmpty() && !m_allowedRanges.contains(range)) {
|
||||||
m_allowedRanges.append(range);
|
m_allowedRanges.append(range);
|
||||||
@@ -242,7 +260,11 @@ bool KillSwitch::enablePeerTraffic(const QJsonObject &configStr) {
|
|||||||
config.m_secondaryDnsServer = configStr.value(amnezia::configKey::dns2).toString();
|
config.m_secondaryDnsServer = configStr.value(amnezia::configKey::dns2).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
config.m_serverPublicKey = "openvpn";
|
config.m_ifname = configStr.value("ifname").toString();
|
||||||
|
const QString protocolName = configStr.value(amnezia::configKey::vpnProto).toString();
|
||||||
|
const QString pubkey = configStr.value(protocolName + "_config_data").toObject()
|
||||||
|
.value(amnezia::configKey::serverPubKey).toString();
|
||||||
|
config.m_serverPublicKey = pubkey.isEmpty() ? QStringLiteral("openvpn") : pubkey;
|
||||||
config.m_serverIpv4Gateway = configStr.value("vpnGateway").toString();
|
config.m_serverIpv4Gateway = configStr.value("vpnGateway").toString();
|
||||||
config.m_serverIpv4AddrIn = configStr.value("vpnServer").toString();
|
config.m_serverIpv4AddrIn = configStr.value("vpnServer").toString();
|
||||||
int vpnAdapterIndex = resolveVpnAdapterIndex(configStr);
|
int vpnAdapterIndex = resolveVpnAdapterIndex(configStr);
|
||||||
@@ -306,10 +328,11 @@ bool KillSwitch::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIn
|
|||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
Q_UNUSED(vpnAdapterIndex)
|
Q_UNUSED(vpnAdapterIndex)
|
||||||
const int resolvedIndex = resolveVpnAdapterIndex(configStr);
|
const int resolvedIndex = resolveVpnAdapterIndex(configStr);
|
||||||
|
const QString ifname = configStr.value("ifname").toString();
|
||||||
if (configStr.value("splitTunnelType").toInt() != 0) {
|
if (configStr.value("splitTunnelType").toInt() != 0) {
|
||||||
WindowsFirewall::create(this)->allowAllTraffic();
|
WindowsFirewall::create(this)->allowAllTraffic();
|
||||||
}
|
}
|
||||||
return WindowsFirewall::create(this)->enableInterface(resolvedIndex);
|
return WindowsFirewall::create(this)->enableInterface(resolvedIndex, ifname);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ public:
|
|||||||
bool init();
|
bool init();
|
||||||
bool refresh(bool enabled);
|
bool refresh(bool enabled);
|
||||||
bool disableKillSwitch();
|
bool disableKillSwitch();
|
||||||
|
bool disableKillSwitchForTunnel(const QString& ifname, const QStringList& remainingRanges);
|
||||||
bool disableAllTraffic();
|
bool disableAllTraffic();
|
||||||
bool enablePeerTraffic(const QJsonObject &configStr);
|
bool enablePeerTraffic(const QJsonObject &configStr);
|
||||||
bool enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIndex);
|
bool enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIndex);
|
||||||
bool resetAllowedRange(const QStringList &ranges);
|
bool resetAllowedRange(const QStringList &ranges);
|
||||||
bool addAllowedRange(const QStringList &ranges);
|
bool addAllowedRange(const QString &ifname, const QStringList &ranges);
|
||||||
bool isStrictKillSwitchEnabled();
|
bool isStrictKillSwitchEnabled();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
Reference in New Issue
Block a user