#include "connectionController.h" #include #include "core/configurators/configuratorBase.h" #include "core/utils/protocolEnum.h" #include "core/protocols/protocolUtils.h" #include "core/utils/constants/configKeys.h" #include "core/utils/constants/protocolConstants.h" #include "core/utils/utilities.h" #include "core/utils/networkUtilities.h" #include "core/utils/serverConfigUtils.h" #include "version.h" #include "core/utils/containerEnum.h" #include "core/utils/containers/containerUtils.h" #include "core/utils/protocolEnum.h" #include "core/models/containerConfig.h" #include "core/models/protocolConfig.h" using namespace amnezia; using namespace ProtocolUtils; ConnectionController::ConnectionController(SecureServersRepository* serversRepository, SecureAppSettingsRepository* appSettingsRepository, VpnConnection* vpnConnection, QObject* parent) : QObject(parent), m_serversRepository(serversRepository), m_appSettingsRepository(appSettingsRepository), m_vpnConnection(vpnConnection) { connect(m_vpnConnection, &VpnConnection::connectionStateChanged, this, &ConnectionController::connectionStateChanged); connect(this, &ConnectionController::openConnectionRequested, m_vpnConnection, &VpnConnection::connectToVpn, Qt::QueuedConnection); connect(this, &ConnectionController::closeConnectionRequested, m_vpnConnection, &VpnConnection::disconnectFromVpn, Qt::QueuedConnection); connect(this, &ConnectionController::setConnectionStateRequested, m_vpnConnection, &VpnConnection::setConnectionState, Qt::QueuedConnection); connect(this, &ConnectionController::killSwitchModeChangedRequested, m_vpnConnection, &VpnConnection::onKillSwitchModeChanged, Qt::QueuedConnection); #ifdef Q_OS_ANDROID connect(this, &ConnectionController::restoreConnectionRequested, m_vpnConnection, &VpnConnection::restoreConnection, Qt::QueuedConnection); #endif } bool ConnectionController::isConnected() const { return m_vpnConnection && m_vpnConnection->connectionState() == Vpn::ConnectionState::Connected; } void ConnectionController::setConnectionState(Vpn::ConnectionState state) { if (m_vpnConnection) { emit setConnectionStateRequested(state); } } ErrorCode ConnectionController::prepareConnection(const QString &serverId, QJsonObject& vpnConfiguration, DockerContainer& container) { if (!isServiceReady()) { return ErrorCode::AmneziaServiceNotRunning; } ContainerConfig containerConfigModel; QPair dns; QString hostName; QString description; int configVersion = 0; bool isApiConfig = false; const auto kind = m_serversRepository->serverKind(serverId); switch (kind) { case serverConfigUtils::ConfigType::SelfHostedAdmin: { const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId); if (!cfg.has_value()) return ErrorCode::InternalError; container = cfg->defaultContainer; containerConfigModel = cfg->containerConfig(container); dns = { cfg->dns1, cfg->dns2 }; hostName = cfg->hostName; description = cfg->description; break; } case serverConfigUtils::ConfigType::SelfHostedUser: { const auto cfg = m_serversRepository->selfHostedUserConfig(serverId); if (!cfg.has_value()) return ErrorCode::InternalError; container = cfg->defaultContainer; containerConfigModel = cfg->containerConfig(container); dns = { cfg->dns1, cfg->dns2 }; hostName = cfg->hostName; description = cfg->description; break; } case serverConfigUtils::ConfigType::Native: { const auto cfg = m_serversRepository->nativeConfig(serverId); if (!cfg.has_value()) return ErrorCode::InternalError; container = cfg->defaultContainer; containerConfigModel = cfg->containerConfig(container); dns = { cfg->dns1, cfg->dns2 }; hostName = cfg->hostName; description = cfg->description; break; } case serverConfigUtils::ConfigType::AmneziaPremiumV2: case serverConfigUtils::ConfigType::AmneziaFreeV3: case serverConfigUtils::ConfigType::ExternalPremium: { const auto cfg = m_serversRepository->apiV2Config(serverId); if (!cfg.has_value()) return ErrorCode::InternalError; container = cfg->defaultContainer; containerConfigModel = cfg->containerConfig(container); dns = { cfg->dns1, cfg->dns2 }; hostName = cfg->hostName; description = cfg->description; configVersion = serverConfigUtils::ConfigSource::AmneziaGateway; isApiConfig = true; break; } case serverConfigUtils::ConfigType::AmneziaPremiumV1: case serverConfigUtils::ConfigType::AmneziaFreeV2: return ErrorCode::InternalError; case serverConfigUtils::ConfigType::Invalid: default: return ErrorCode::InternalError; } if (!isContainerSupported(container)) { return ErrorCode::NotSupportedOnThisPlatform; } if (dns.first.isEmpty() || !NetworkUtilities::checkIPv4Format(dns.first)) { if (m_appSettingsRepository->useAmneziaDns()) { dns.first = protocols::dns::amneziaDnsIp; } else { dns.first = m_appSettingsRepository->primaryDns(); } } if (dns.second.isEmpty() || !NetworkUtilities::checkIPv4Format(dns.second)) { dns.second = m_appSettingsRepository->secondaryDns(); } vpnConfiguration = createConnectionConfiguration(dns, isApiConfig, hostName, description, configVersion, containerConfigModel, container); return ErrorCode::NoError; } ErrorCode ConnectionController::openConnection(const QString &serverId) { QJsonObject vpnConfiguration; DockerContainer container; ErrorCode errorCode = prepareConnection(serverId, vpnConfiguration, container); if (errorCode != ErrorCode::NoError) { return errorCode; } emit openConnectionRequested(serverId, container, vpnConfiguration); return ErrorCode::NoError; } void ConnectionController::closeConnection() { if (m_vpnConnection) { emit closeConnectionRequested(); } } #ifdef Q_OS_ANDROID void ConnectionController::restoreConnection() { if (m_vpnConnection) { emit restoreConnectionRequested(); } } #endif void ConnectionController::onKillSwitchModeChanged(bool enabled) { if (m_vpnConnection) { emit killSwitchModeChangedRequested(enabled); } } ErrorCode ConnectionController::lastConnectionError() const { return m_vpnConnection->lastError(); } QJsonObject ConnectionController::createConnectionConfiguration(const QPair &dns, bool isApiConfig, const QString &hostName, const QString &description, int configVersion, const ContainerConfig &containerConfig, DockerContainer container) { QJsonObject vpnConfiguration {}; if (ContainerUtils::containerService(container) == ServiceType::Other) { return vpnConfiguration; } Proto proto = ContainerUtils::defaultProtocol(container); ConnectionSettings connectionSettings = { { dns.first, dns.second }, isApiConfig, { m_appSettingsRepository->isSitesSplitTunnelingEnabled(), m_appSettingsRepository->routeMode() } }; auto configurator = ConfiguratorBase::create(proto, nullptr); ProtocolConfig processedConfig = configurator->processConfigWithLocalSettings(connectionSettings, containerConfig.protocolConfig); QJsonObject vpnConfigData = processedConfig.getClientConfigJson(); if (ContainerUtils::isAwgContainer(container) || container == DockerContainer::WireGuard) { if (vpnConfigData[configKey::mtu].toString().isEmpty()) { vpnConfigData[configKey::mtu] = ContainerUtils::isAwgContainer(container) ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu; } } vpnConfiguration.insert(ProtocolUtils::key_proto_config_data(proto), vpnConfigData); vpnConfiguration[configKey::vpnProto] = ProtocolUtils::protoToString(proto); vpnConfiguration[configKey::dns1] = dns.first; vpnConfiguration[configKey::dns2] = dns.second; vpnConfiguration[configKey::hostName] = hostName; vpnConfiguration[configKey::description] = description; vpnConfiguration[configKey::configVersion] = configVersion; return vpnConfiguration; } bool ConnectionController::isServiceReady() const { #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) return Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true); #else return true; #endif } bool ConnectionController::isContainerSupported(DockerContainer container) const { return ContainerUtils::isSupportedByCurrentPlatform(container); }