Compare commits

..

1 Commits

Author SHA1 Message Date
vladimir.kuznetsov
6caf958bb3 Added Accessible for main menu tabs and some PageSettings items 2023-10-04 00:31:40 +05:00
148 changed files with 3581 additions and 9674 deletions

View File

@@ -1,12 +1,7 @@
name: 'Deploy workflow'
on:
push:
branches:
- '**'
env:
QT_MIRROR: https://mirrors.ocf.berkeley.edu/qt/ # https://download.qt.io/static/mirrorlist/
on: [push]
jobs:
Build-Linux-Ubuntu:
@@ -30,7 +25,7 @@ jobs:
setup-python: 'true'
tools: 'tools_ifw'
set-env: 'true'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
extra: '--external 7z'
- name: 'Get sources'
uses: actions/checkout@v3
@@ -94,7 +89,7 @@ jobs:
setup-python: 'true'
tools: 'tools_ifw'
set-env: 'true'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
extra: '--external 7z'
- name: 'Setup mvsc'
uses: ilammy/msvc-dev-cmd@v1
@@ -124,14 +119,15 @@ jobs:
# ------------------------------------------------------
Build-iOS:
name: 'Build-iOS'
Build-IOS:
name: 'Build-IOS'
runs-on: macos-12
env:
QT_VERSION: 6.5.2
steps:
# Just select XCode
- name: 'Setup xcode'
uses: maxim-lobanov/setup-xcode@v1
with:
@@ -147,7 +143,6 @@ jobs:
arch: 'clang_64'
dir: ${{ runner.temp }}
set-env: 'true'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Install iOS Qt'
uses: jurplel/install-qt-action@v3
@@ -159,7 +154,7 @@ jobs:
dir: ${{ runner.temp }}
setup-python: 'true'
set-env: 'true'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
extra: '--external 7z'
- name: 'Install go'
uses: actions/setup-go@v3
@@ -179,7 +174,7 @@ jobs:
- name: 'Setup ccache'
uses: hendrikmuhs/ccache-action@v1.2
- name: 'Install dependencies'
- name: Install dependencies
run: pip install jsonschema jinja2
- name: 'Build project'
@@ -237,7 +232,7 @@ jobs:
setup-python: 'true'
tools: 'tools_ifw'
set-env: 'true'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
extra: '--external 7z'
- name: 'Get sources'
uses: actions/checkout@v3
@@ -301,7 +296,7 @@ jobs:
dir: ${{ runner.temp }}
setup-python: 'true'
set-env: 'true'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
extra: '--external 7z'
- name: 'Install android Qt'
uses: jurplel/install-qt-action@v3
@@ -314,7 +309,7 @@ jobs:
dir: ${{ runner.temp }}
setup-python: 'true'
set-env: 'true'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
extra: '--external 7z'
- name: 'Grant execute permission for qt-cmake'
shell: bash

View File

@@ -1,64 +0,0 @@
name: 'Upload a new version'
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+.[0-9]+'
jobs:
upload:
runs-on: ubuntu-latest
name: upload
steps:
- name: Checkout CMakeLists.txt
uses: actions/checkout@v4
with:
ref: ${{ github.ref_name }}
sparse-checkout: |
CMakeLists.txt
sparse-checkout-cone-mode: false
- name: Verify git tag
run: |
GIT_TAG=${{ github.ref_name }}
CMAKE_TAG=$(grep 'project.*VERSION' CMakeLists.txt | sed -E 's/.* ([0-9]+.[0-9]+.[0-9]+.[0-9]+)$/\1/')
if [[ "$GIT_TAG" == "$CMAKE_TAG" ]]; then
echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are the same. Continuing..."
else
echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are not the same! Cancelling..."
exit 1
fi
- name: Download artifacts from the "${{ github.ref_name }}" tag
uses: robinraju/release-downloader@v1.8
with:
tag: ${{ github.ref_name }}
fileName: "AmneziaVPN_(Linux_|)${{ github.ref_name }}*"
out-file-path: ${{ github.ref_name }}
- name: Upload beta version
uses: jakejarvis/s3-sync-action@master
if: contains(github.event.base_ref, 'dev')
with:
args: --include "AmneziaVPN*" --delete
env:
AWS_S3_BUCKET: updates
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
SOURCE_DIR: ${{ github.ref_name }}
DEST_DIR: beta/${{ github.ref_name }}
- name: Upload stable version
uses: jakejarvis/s3-sync-action@master
if: contains(github.event.base_ref, 'master')
with:
args: --include "AmneziaVPN*" --delete
env:
AWS_S3_BUCKET: updates
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
SOURCE_DIR: ${{ github.ref_name }}
DEST_DIR: stable/${{ github.ref_name }}

6
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "client/3rd/wireguard-apple"]
path = client/3rd/wireguard-apple
url = https://github.com/WireGuard/wireguard-apple
[submodule "client/3rd/OpenVPNAdapter"]
path = client/3rd/OpenVPNAdapter
url = https://github.com/amnezia-vpn/OpenVPNAdapter.git
@@ -22,6 +25,3 @@
[submodule "client/3rd-prebuilt"]
path = client/3rd-prebuilt
url = https://github.com/amnezia-vpn/3rd-prebuilt
[submodule "client/3rd/awg-apple"]
path = client/3rd/awg-apple
url = https://github.com/amnezia-vpn/awg-apple

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
project(${PROJECT} VERSION 4.1.0.1
project(${PROJECT} VERSION 4.0.7.1
DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/"
)

Submodule client/3rd/awg-apple deleted from 233eda6760

1
client/3rd/wireguard-apple vendored Submodule

View File

@@ -50,30 +50,12 @@ endif()
qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/resources.qrc)
# -- i18n begin
set(CMAKE_AUTORCC ON)
set(AMNEZIAVPN_TS_FILES
qt6_add_translations(${PROJECT} TS_FILES
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ru.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_zh_CN.ts
)
file(GLOB_RECURSE AMNEZIAVPN_TS_SOURCES *.qrc *.cpp *.h *.ui)
qt_create_translation(AMNEZIAVPN_QM_FILES ${AMNEZIAVPN_TS_SOURCES} ${AMNEZIAVPN_TS_FILES})
set(QM_FILE_LIST "")
foreach(FILE ${AMNEZIAVPN_QM_FILES})
get_filename_component(QM_FILE_NAME ${FILE} NAME)
list(APPEND QM_FILE_LIST "<file>${QM_FILE_NAME}</file>")
endforeach()
string(REPLACE ";" "" QM_FILE_LIST ${QM_FILE_LIST})
configure_file(${CMAKE_CURRENT_LIST_DIR}/translations/translations.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
qt6_add_resources(QRC ${I18NQRC} ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
# -- i18n end
if(IOS)
#execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/scripts/run-build-cloak.sh)
execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/ios/scripts/openvpn.sh args
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
endif()
@@ -281,7 +263,6 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/awgprotocol.h
)
set(SOURCES ${SOURCES}
@@ -292,7 +273,6 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/awgprotocol.cpp
)
endif()
@@ -342,5 +322,5 @@ if(NOT IOS AND NOT ANDROID)
endif()
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC})
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC})
qt_finalize_target(${PROJECT})

View File

@@ -87,7 +87,6 @@ void AmneziaApplication::init()
m_vpnConnectionThread.start();
initModels();
loadTranslator();
initControllers();
#ifdef Q_OS_ANDROID
@@ -139,8 +138,6 @@ void AmneziaApplication::init()
&ConnectionController::openConnection);
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
&ConnectionController::closeConnection);
connect(this, &AmneziaApplication::translationsUpdated, m_notificationHandler.get(),
&NotificationHandler::onTranslationsUpdated);
m_engine->load(url);
m_systemController->setQmlRoot(m_engine->rootObjects().value(0));
@@ -224,25 +221,33 @@ void AmneziaApplication::loadTranslator()
{
auto locale = m_settings->getAppLanguage();
m_translator.reset(new QTranslator());
updateTranslator(locale);
if (locale != QLocale::English) {
if (m_translator->load(locale, QString("amneziavpn"), QLatin1String("_"), QLatin1String(":/i18n"))) {
if (QCoreApplication::installTranslator(m_translator.get())) {
m_settings->setAppLanguage(locale);
}
}
}
}
void AmneziaApplication::updateTranslator(const QLocale &locale)
{
if (!m_translator->isEmpty()) {
QResource::registerResource(":/translations.qrc");
if (!m_translator->isEmpty())
QCoreApplication::removeTranslator(m_translator.get());
if (locale == QLocale::English) {
m_settings->setAppLanguage(locale);
m_engine->retranslate();
}
QString strFileName = QString(":/translations/amneziavpn") + QLatin1String("_") + locale.name() + ".qm";
if (m_translator->load(strFileName)) {
if (m_translator->load(locale, QString("amneziavpn"), QLatin1String("_"), QLatin1String(":/i18n"))) {
if (QCoreApplication::installTranslator(m_translator.get())) {
m_settings->setAppLanguage(locale);
}
} else {
m_settings->setAppLanguage(QLocale::English);
}
m_engine->retranslate();
m_engine->retranslate();
}
emit translationsUpdated();
}
@@ -279,17 +284,11 @@ void AmneziaApplication::initModels()
{
m_containersModel.reset(new ContainersModel(m_settings, this));
m_engine->rootContext()->setContextProperty("ContainersModel", m_containersModel.get());
connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, m_containersModel.get(),
&ContainersModel::updateContainersConfig);
m_serversModel.reset(new ServersModel(m_settings, this));
m_engine->rootContext()->setContextProperty("ServersModel", m_serversModel.get());
connect(m_serversModel.get(), &ServersModel::currentlyProcessedServerIndexChanged, m_containersModel.get(),
&ContainersModel::setCurrentlyProcessedServerIndex);
connect(m_serversModel.get(), &ServersModel::defaultServerIndexChanged, m_containersModel.get(),
&ContainersModel::setCurrentlyProcessedServerIndex);
connect(m_containersModel.get(), &ContainersModel::containersModelUpdated, m_serversModel.get(),
&ServersModel::updateContainersConfig);
m_languageModel.reset(new LanguageModel(m_settings, this));
m_engine->rootContext()->setContextProperty("LanguageModel", m_languageModel.get());
@@ -298,7 +297,15 @@ void AmneziaApplication::initModels()
m_sitesModel.reset(new SitesModel(m_settings, this));
m_engine->rootContext()->setContextProperty("SitesModel", m_sitesModel.get());
connect(m_containersModel.get(), &ContainersModel::defaultContainerChanged, this, [this]() {
if (m_containersModel->getDefaultContainer() == DockerContainer::WireGuard
&& m_sitesModel->getRouteMode() != Settings::RouteMode::VpnAllSites) {
m_sitesModel->setRouteMode(Settings::RouteMode::VpnAllSites);
emit m_pageController->showNotificationMessage(
tr("Split tunneling for WireGuard is not implemented, the option was disabled"));
}
});
m_protocolsModel.reset(new ProtocolsModel(m_settings, this));
m_engine->rootContext()->setContextProperty("ProtocolsModel", m_protocolsModel.get());
@@ -311,11 +318,8 @@ void AmneziaApplication::initModels()
m_cloakConfigModel.reset(new CloakConfigModel(this));
m_engine->rootContext()->setContextProperty("CloakConfigModel", m_cloakConfigModel.get());
m_wireGuardConfigModel.reset(new WireGuardConfigModel(this));
m_engine->rootContext()->setContextProperty("WireGuardConfigModel", m_wireGuardConfigModel.get());
m_awgConfigModel.reset(new AwgConfigModel(this));
m_engine->rootContext()->setContextProperty("AwgConfigModel", m_awgConfigModel.get());
m_wireguardConfigModel.reset(new WireGuardConfigModel(this));
m_engine->rootContext()->setContextProperty("WireGuardConfigModel", m_wireguardConfigModel.get());
#ifdef Q_OS_WINDOWS
m_ikev2ConfigModel.reset(new Ikev2ConfigModel(this));
@@ -324,11 +328,6 @@ void AmneziaApplication::initModels()
m_sftpConfigModel.reset(new SftpConfigModel(this));
m_engine->rootContext()->setContextProperty("SftpConfigModel", m_sftpConfigModel.get());
m_clientManagementModel.reset(new ClientManagementModel(m_settings, this));
m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get());
connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, m_clientManagementModel.get(),
&ClientManagementModel::appendClient);
}
void AmneziaApplication::initControllers()
@@ -336,9 +335,6 @@ void AmneziaApplication::initControllers()
m_connectionController.reset(new ConnectionController(m_serversModel, m_containersModel, m_vpnConnection));
m_engine->rootContext()->setContextProperty("ConnectionController", m_connectionController.get());
connect(this, &AmneziaApplication::translationsUpdated, m_connectionController.get(),
&ConnectionController::onTranslationsUpdated);
m_pageController.reset(new PageController(m_serversModel, m_settings));
m_engine->rootContext()->setContextProperty("PageController", m_pageController.get());
@@ -354,12 +350,12 @@ void AmneziaApplication::initControllers()
m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_clientManagementModel, m_settings, m_configurator));
m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_settings, m_configurator));
m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get());
m_settingsController.reset(new SettingsController(m_serversModel, m_containersModel, m_languageModel, m_settings));
m_engine->rootContext()->setContextProperty("SettingsController", m_settingsController.get());
if (m_settingsController->isAutoConnectEnabled() && m_serversModel->getDefaultServerIndex() >= 0) {
if (m_settingsController->isAutoStartEnabled() && m_serversModel->getDefaultServerIndex() >= 0) {
QTimer::singleShot(1000, this, [this]() { m_connectionController->openConnection(); });
}

View File

@@ -31,7 +31,6 @@
#ifdef Q_OS_WINDOWS
#include "ui/models/protocols/ikev2ConfigModel.h"
#endif
#include "ui/models/protocols/awgConfigModel.h"
#include "ui/models/protocols/openvpnConfigModel.h"
#include "ui/models/protocols/shadowsocksConfigModel.h"
#include "ui/models/protocols/wireguardConfigModel.h"
@@ -39,7 +38,6 @@
#include "ui/models/servers_model.h"
#include "ui/models/services/sftpConfigModel.h"
#include "ui/models/sites_model.h"
#include "ui/models/clientManagementModel.h"
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
@@ -95,13 +93,11 @@ private:
QSharedPointer<LanguageModel> m_languageModel;
QSharedPointer<ProtocolsModel> m_protocolsModel;
QSharedPointer<SitesModel> m_sitesModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel;
QScopedPointer<OpenVpnConfigModel> m_openVpnConfigModel;
QScopedPointer<ShadowSocksConfigModel> m_shadowSocksConfigModel;
QScopedPointer<CloakConfigModel> m_cloakConfigModel;
QScopedPointer<WireGuardConfigModel> m_wireGuardConfigModel;
QScopedPointer<AwgConfigModel> m_awgConfigModel;
QScopedPointer<WireGuardConfigModel> m_wireguardConfigModel;
#ifdef Q_OS_WINDOWS
QScopedPointer<Ikev2ConfigModel> m_ikev2ConfigModel;
#endif

View File

@@ -45,7 +45,6 @@
android:label="-- %%INSERT_APP_NAME%% --"
android:screenOrientation="unspecified"
android:launchMode="singleInstance"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<!-- android:theme="@style/splashScreenTheme"-->

View File

@@ -138,8 +138,8 @@ android {
resConfig "en"
minSdkVersion = 24
targetSdkVersion = 34
versionCode 39 // Change to a higher number
versionName "4.1.0" // Change to a higher number
versionCode 32 // Change to a higher number
versionName "3.0.9" // Change to a higher number
javaCompileOptions.annotationProcessorOptions.arguments = [
"room.schemaLocation": "${qtAndroidDir}/schemas".toString()

View File

@@ -70,15 +70,6 @@ public class BadConfigException extends Exception {
EXCLUDED_APPLICATIONS("ExcludedApplications"),
INCLUDED_APPLICATIONS("IncludedApplications"),
LISTEN_PORT("ListenPort"),
JC("Jc"),
JMIN("Jmin"),
JMAX("Jmax"),
S1("S1"),
S2("S2"),
H1("H1"),
H2("H2"),
H3("H3"),
H4("H4"),
MTU("MTU"),
PERSISTENT_KEEPALIVE("PersistentKeepalive"),
PRE_SHARED_KEY("PresharedKey"),

View File

@@ -1,509 +0,0 @@
/*
* Copyright (C) 2012-2017 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package com.wireguard.config;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import androidx.annotation.NonNull;
/**
* Class that represents a range of IP addresses. This range could be a proper subnet, but that's
* not necessarily the case (see {@code getPrefix} and {@code toSubnets}).
*/
public class IPRange implements Comparable<IPRange>
{
private final byte[] mBitmask = { (byte)0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
private byte[] mFrom;
private byte[] mTo;
private Integer mPrefix;
/**
* Determine if the range is a proper subnet and, if so, what the network prefix is.
*/
private void determinePrefix()
{
boolean matching = true;
mPrefix = mFrom.length * 8;
for (int i = 0; i < mFrom.length; i++)
{
for (int bit = 0; bit < 8; bit++)
{
if (matching)
{
if ((mFrom[i] & mBitmask[bit]) != (mTo[i] & mBitmask[bit]))
{
mPrefix = (i * 8) + bit;
matching = false;
}
}
else
{
if ((mFrom[i] & mBitmask[bit]) != 0 || (mTo[i] & mBitmask[bit]) == 0)
{
mPrefix = null;
return;
}
}
}
}
}
private IPRange(byte[] from, byte[] to)
{
mFrom = from;
mTo = to;
determinePrefix();
}
public IPRange(String from, String to) throws UnknownHostException
{
this(Utils.parseInetAddress(from), Utils.parseInetAddress(to));
}
public IPRange(InetAddress from, InetAddress to)
{
initializeFromRange(from, to);
}
private void initializeFromRange(InetAddress from, InetAddress to)
{
byte[] fa = from.getAddress(), ta = to.getAddress();
if (fa.length != ta.length)
{
throw new IllegalArgumentException("Invalid range");
}
if (compareAddr(fa, ta) < 0)
{
mFrom = fa;
mTo = ta;
}
else
{
mTo = fa;
mFrom = ta;
}
determinePrefix();
}
public IPRange(String base, int prefix) throws UnknownHostException
{
this(Utils.parseInetAddress(base), prefix);
}
public IPRange(InetAddress base, int prefix)
{
this(base.getAddress(), prefix);
}
private IPRange(byte[] from, int prefix)
{
initializeFromCIDR(from, prefix);
}
private void initializeFromCIDR(byte[] from, int prefix)
{
if (from.length != 4 && from.length != 16)
{
throw new IllegalArgumentException("Invalid address");
}
if (prefix < 0 || prefix > from.length * 8)
{
throw new IllegalArgumentException("Invalid prefix");
}
byte[] to = from.clone();
byte mask = (byte)(0xff << (8 - prefix % 8));
int i = prefix / 8;
if (i < from.length)
{
from[i] = (byte)(from[i] & mask);
to[i] = (byte)(to[i] | ~mask);
Arrays.fill(from, i+1, from.length, (byte)0);
Arrays.fill(to, i+1, to.length, (byte)0xff);
}
mFrom = from;
mTo = to;
mPrefix = prefix;
}
public IPRange(String cidr) throws UnknownHostException
{
/* only verify the basic structure */
if (!cidr.matches("(?i)^(([0-9.]+)|([0-9a-f:]+))(-(([0-9.]+)|([0-9a-f:]+))|(/\\d+))?$"))
{
throw new IllegalArgumentException("Invalid CIDR or range notation");
}
if (cidr.contains("-"))
{
String[] parts = cidr.split("-");
InetAddress from = InetAddress.getByName(parts[0]);
InetAddress to = InetAddress.getByName(parts[1]);
initializeFromRange(from, to);
}
else
{
String[] parts = cidr.split("/");
InetAddress addr = InetAddress.getByName(parts[0]);
byte[] base = addr.getAddress();
int prefix = base.length * 8;
if (parts.length > 1)
{
prefix = Integer.parseInt(parts[1]);
}
initializeFromCIDR(base, prefix);
}
}
/**
* Returns the first address of the range. The network ID in case this is a proper subnet.
*/
public InetAddress getFrom()
{
try
{
return InetAddress.getByAddress(mFrom);
}
catch (UnknownHostException ignored)
{
return null;
}
}
/**
* Returns the last address of the range.
*/
public InetAddress getTo()
{
try
{
return InetAddress.getByAddress(mTo);
}
catch (UnknownHostException ignored)
{
return null;
}
}
/**
* If this range is a proper subnet returns its prefix, otherwise returns null.
*/
public Integer getPrefix()
{
return mPrefix;
}
@Override
public int compareTo(@NonNull IPRange other)
{
int cmp = compareAddr(mFrom, other.mFrom);
if (cmp == 0)
{ /* smaller ranges first */
cmp = compareAddr(mTo, other.mTo);
}
return cmp;
}
@Override
public boolean equals(Object o)
{
if (o == null || !(o instanceof IPRange))
{
return false;
}
return this == o || compareTo((IPRange)o) == 0;
}
@Override
public String toString()
{
try
{
if (mPrefix != null)
{
return InetAddress.getByAddress(mFrom).getHostAddress() + "/" + mPrefix;
}
return InetAddress.getByAddress(mFrom).getHostAddress() + "-" +
InetAddress.getByAddress(mTo).getHostAddress();
}
catch (UnknownHostException ignored)
{
return super.toString();
}
}
private int compareAddr(byte a[], byte b[])
{
if (a.length != b.length)
{
return (a.length < b.length) ? -1 : 1;
}
for (int i = 0; i < a.length; i++)
{
if (a[i] != b[i])
{
if (((int)a[i] & 0xff) < ((int)b[i] & 0xff))
{
return -1;
}
else
{
return 1;
}
}
}
return 0;
}
/**
* Check if this range fully contains the given range.
*/
public boolean contains(IPRange range)
{
return compareAddr(mFrom, range.mFrom) <= 0 && compareAddr(range.mTo, mTo) <= 0;
}
/**
* Check if this and the given range overlap.
*/
public boolean overlaps(IPRange range)
{
return !(compareAddr(mTo, range.mFrom) < 0 || compareAddr(range.mTo, mFrom) < 0);
}
private byte[] dec(byte[] addr)
{
for (int i = addr.length - 1; i >= 0; i--)
{
if (--addr[i] != (byte)0xff)
{
break;
}
}
return addr;
}
private byte[] inc(byte[] addr)
{
for (int i = addr.length - 1; i >= 0; i--)
{
if (++addr[i] != 0)
{
break;
}
}
return addr;
}
/**
* Remove the given range from the current range. Returns a list of resulting ranges (these are
* not proper subnets). At most two ranges are returned, in case the given range is contained in
* this but does not equal it, which would result in an empty list (which is also the case if
* this range is fully contained in the given range).
*/
public List<IPRange> remove(IPRange range)
{
ArrayList<IPRange> list = new ArrayList<>();
if (!overlaps(range))
{ /* | this | or | this |
* | range | | range | */
list.add(this);
}
else if (!range.contains(this))
{ /* we are not completely removed, so none of these cases applies:
* | this | or | this | or | this |
* | range | | range | | range | */
if (compareAddr(mFrom, range.mFrom) < 0 && compareAddr(range.mTo, mTo) < 0)
{ /* the removed range is completely within our boundaries:
* | this |
* | range | */
list.add(new IPRange(mFrom, dec(range.mFrom.clone())));
list.add(new IPRange(inc(range.mTo.clone()), mTo));
}
else
{ /* one end is within our boundaries the other at or outside it:
* | this | or | this | or | this | or | this |
* | range | | range | | range | | range | */
byte[] from = compareAddr(mFrom, range.mFrom) < 0 ? mFrom : inc(range.mTo.clone());
byte[] to = compareAddr(mTo, range.mTo) > 0 ? mTo : dec(range.mFrom.clone());
list.add(new IPRange(from, to));
}
}
return list;
}
private boolean adjacent(IPRange range)
{
if (compareAddr(mTo, range.mFrom) < 0)
{
byte[] to = inc(mTo.clone());
return compareAddr(to, range.mFrom) == 0;
}
byte[] from = dec(mFrom.clone());
return compareAddr(from, range.mTo) == 0;
}
/**
* Merge two adjacent or overlapping ranges, returns null if it's not possible to merge them.
*/
public IPRange merge(IPRange range)
{
if (overlaps(range))
{
if (contains(range))
{
return this;
}
else if (range.contains(this))
{
return range;
}
}
else if (!adjacent(range))
{
return null;
}
byte[] from = compareAddr(mFrom, range.mFrom) < 0 ? mFrom : range.mFrom;
byte[] to = compareAddr(mTo, range.mTo) > 0 ? mTo : range.mTo;
return new IPRange(from, to);
}
/**
* Split the given range into a sorted list of proper subnets.
*/
public List<IPRange> toSubnets()
{
ArrayList<IPRange> list = new ArrayList<>();
if (mPrefix != null)
{
list.add(this);
}
else
{
int i = 0, bit = 0, prefix, netmask, common_byte, common_bit;
int from_cur, from_prev = 0, to_cur, to_prev = 1;
boolean from_full = true, to_full = true;
byte[] from = mFrom.clone();
byte[] to = mTo.clone();
/* find a common prefix */
while (i < from.length && (from[i] & mBitmask[bit]) == (to[i] & mBitmask[bit]))
{
if (++bit == 8)
{
bit = 0;
i++;
}
}
prefix = i * 8 + bit;
/* at this point we know that the addresses are either equal, or that the
* current bits in the 'from' and 'to' addresses are 0 and 1, respectively.
* we now look at the rest of the bits as two binary trees (0=left, 1=right)
* where 'from' and 'to' are both leaf nodes. all leaf nodes between these
* nodes are addresses contained in the range. to collect them as subnets
* we follow the trees from both leaf nodes to their root node and record
* all complete subtrees (right for from, left for to) we come across as
* subnets. in that process host bits are zeroed out. if both addresses
* are equal we won't enter the loop below.
* 0_____|_____1 for the 'from' address we assume we start on a
* 0__|__ 1 0__|__1 left subtree (0) and follow the left edges until
* _|_ _|_ _|_ _|_ we reach the root of this subtree, which is
* | | | | | | | | either the root of this whole 'from'-subtree
* 0 1 0 1 0 1 0 1 (causing us to leave the loop) or the root node
* of the right subtree (1) of another node (which actually could be the
* leaf node we start from). that whole subtree gets recorded as subnet.
* next we follow the right edges to the root of that subtree which again is
* either the 'from'-root or the root node in the left subtree (0) of
* another node. the complete right subtree of that node is the next subnet
* we record. from there we assume that we are in that right subtree and
* recursively follow right edges to its root. for the 'to' address the
* procedure is exactly the same but with left and right reversed.
*/
if (++bit == 8)
{
bit = 0;
i++;
}
common_byte = i;
common_bit = bit;
netmask = from.length * 8;
for (i = from.length - 1; i >= common_byte; i--)
{
int bit_min = (i == common_byte) ? common_bit : 0;
for (bit = 7; bit >= bit_min; bit--)
{
byte mask = mBitmask[bit];
from_cur = from[i] & mask;
if (from_prev == 0 && from_cur != 0)
{ /* 0 -> 1: subnet is the whole current (right) subtree */
list.add(new IPRange(from.clone(), netmask));
from_full = false;
}
else if (from_prev != 0 && from_cur == 0)
{ /* 1 -> 0: invert bit to switch to right subtree and add it */
from[i] ^= mask;
list.add(new IPRange(from.clone(), netmask));
from_cur = 1;
}
/* clear the current bit */
from[i] &= ~mask;
from_prev = from_cur;
to_cur = to[i] & mask;
if (to_prev != 0 && to_cur == 0)
{ /* 1 -> 0: subnet is the whole current (left) subtree */
list.add(new IPRange(to.clone(), netmask));
to_full = false;
}
else if (to_prev == 0 && to_cur != 0)
{ /* 0 -> 1: invert bit to switch to left subtree and add it */
to[i] ^= mask;
list.add(new IPRange(to.clone(), netmask));
to_cur = 0;
}
/* clear the current bit */
to[i] &= ~mask;
to_prev = to_cur;
netmask--;
}
}
if (from_full && to_full)
{ /* full subnet (from=to or from=0.. and to=1.. after common prefix) - not reachable
* due to the shortcut at the top */
list.add(new IPRange(from.clone(), prefix));
}
else if (from_full)
{ /* full from subnet (from=0.. after prefix) */
list.add(new IPRange(from.clone(), prefix + 1));
}
else if (to_full)
{ /* full to subnet (to=1.. after prefix) */
list.add(new IPRange(to.clone(), prefix + 1));
}
}
Collections.sort(list);
return list;
}
}

View File

@@ -1,223 +0,0 @@
/*
* Copyright (C) 2012-2017 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package com.wireguard.config;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
/**
* Class that represents a set of IP address ranges (not necessarily proper subnets) and allows
* modifying the set and enumerating the resulting subnets.
*/
public class IPRangeSet implements Iterable<IPRange>
{
private TreeSet<IPRange> mRanges = new TreeSet<>();
/**
* Parse the given string (space separated ranges in CIDR or range notation) and return the
* resulting set or {@code null} if the string was invalid. An empty set is returned if the given string
* is {@code null}.
*/
public static IPRangeSet fromString(String ranges)
{
IPRangeSet set = new IPRangeSet();
if (ranges != null)
{
for (String range : ranges.split("\\s+"))
{
try
{
set.add(new IPRange(range));
}
catch (Exception unused)
{ /* besides due to invalid strings exceptions might get thrown if the string
* contains a hostname (NetworkOnMainThreadException) */
return null;
}
}
}
return set;
}
/**
* Add a range to this set. Automatically gets merged with existing ranges.
*/
public void add(IPRange range)
{
if (mRanges.contains(range))
{
return;
}
reinsert:
while (true)
{
Iterator<IPRange> iterator = mRanges.iterator();
while (iterator.hasNext())
{
IPRange existing = iterator.next();
IPRange replacement = existing.merge(range);
if (replacement != null)
{
iterator.remove();
range = replacement;
continue reinsert;
}
}
mRanges.add(range);
break;
}
}
/**
* Add all ranges from the given set.
*/
public void add(IPRangeSet ranges)
{
if (ranges == this)
{
return;
}
for (IPRange range : ranges.mRanges)
{
add(range);
}
}
/**
* Add all ranges from the given collection to this set.
*/
public void addAll(Collection<? extends IPRange> coll)
{
for (IPRange range : coll)
{
add(range);
}
}
/**
* Remove the given range from this set. Existing ranges are automatically adjusted.
*/
public void remove(IPRange range)
{
ArrayList <IPRange> additions = new ArrayList<>();
Iterator<IPRange> iterator = mRanges.iterator();
while (iterator.hasNext())
{
IPRange existing = iterator.next();
List<IPRange> result = existing.remove(range);
if (result.size() == 0)
{
iterator.remove();
}
else if (!result.get(0).equals(existing))
{
iterator.remove();
additions.addAll(result);
}
}
mRanges.addAll(additions);
}
/**
* Remove the given ranges from ranges in this set.
*/
public void remove(IPRangeSet ranges)
{
if (ranges == this)
{
mRanges.clear();
return;
}
for (IPRange range : ranges.mRanges)
{
remove(range);
}
}
/**
* Get all the subnets derived from all the ranges in this set.
*/
public Iterable<IPRange> subnets()
{
return new Iterable<IPRange>()
{
@Override
public Iterator<IPRange> iterator()
{
return new Iterator<IPRange>()
{
private Iterator<IPRange> mIterator = mRanges.iterator();
private List<IPRange> mSubnets;
@Override
public boolean hasNext()
{
return (mSubnets != null && mSubnets.size() > 0) || mIterator.hasNext();
}
@Override
public IPRange next()
{
if (mSubnets == null || mSubnets.size() == 0)
{
IPRange range = mIterator.next();
mSubnets = range.toSubnets();
}
return mSubnets.remove(0);
}
@Override
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
};
}
@Override
public Iterator<IPRange> iterator()
{
return mRanges.iterator();
}
/**
* Returns the number of ranges, not subnets.
*/
public int size()
{
return mRanges.size();
}
@Override
public String toString()
{ /* we could use TextUtils, but that causes the unit tests to fail */
StringBuilder sb = new StringBuilder();
for (IPRange range : mRanges)
{
if (sb.length() > 0)
{
sb.append(" ");
}
sb.append(range.toString());
}
return sb.toString();
}
}

View File

@@ -44,15 +44,6 @@ public final class Interface {
private final KeyPair keyPair;
private final Optional<Integer> listenPort;
private final Optional<Integer> mtu;
private final Optional<Integer> jc;
private final Optional<Integer> jmin;
private final Optional<Integer> jmax;
private final Optional<Integer> s1;
private final Optional<Integer> s2;
private final Optional<Long> h1;
private final Optional<Long> h2;
private final Optional<Long> h3;
private final Optional<Long> h4;
private Interface(final Builder builder) {
// Defensively copy to ensure immutability even if the Builder is reused.
@@ -65,15 +56,6 @@ public final class Interface {
keyPair = Objects.requireNonNull(builder.keyPair, "Interfaces must have a private key");
listenPort = builder.listenPort;
mtu = builder.mtu;
jc = builder.jc;
jmax = builder.jmax;
jmin = builder.jmin;
s1 = builder.s1;
s2 = builder.s2;
h1 = builder.h1;
h2 = builder.h2;
h3 = builder.h3;
h4 = builder.h4;
}
/**
@@ -113,33 +95,6 @@ public final class Interface {
case "privatekey":
builder.parsePrivateKey(attribute.getValue());
break;
case "jc":
builder.parseJc(attribute.getValue());
break;
case "jmin":
builder.parseJmin(attribute.getValue());
break;
case "jmax":
builder.parseJmax(attribute.getValue());
break;
case "s1":
builder.parseS1(attribute.getValue());
break;
case "s2":
builder.parseS2(attribute.getValue());
break;
case "h1":
builder.parseH1(attribute.getValue());
break;
case "h2":
builder.parseH2(attribute.getValue());
break;
case "h3":
builder.parseH3(attribute.getValue());
break;
case "h4":
builder.parseH4(attribute.getValue());
break;
default:
throw new BadConfigException(
Section.INTERFACE, Location.TOP_LEVEL, Reason.UNKNOWN_ATTRIBUTE, attribute.getKey());
@@ -156,9 +111,7 @@ public final class Interface {
return addresses.equals(other.addresses) && dnsServers.equals(other.dnsServers)
&& excludedApplications.equals(other.excludedApplications)
&& includedApplications.equals(other.includedApplications) && keyPair.equals(other.keyPair)
&& listenPort.equals(other.listenPort) && mtu.equals(other.mtu) && jc.equals(other.jc) && jmin.equals(other.jmin)
&& jmax.equals(other.jmax) && s1.equals(other.s1) && s2.equals(other.s2) && h1.equals(other.h1) && h2.equals(other.h2)
&& h3.equals(other.h3) && h4.equals(other.h4);
&& listenPort.equals(other.listenPort) && mtu.equals(other.mtu);
}
/**
@@ -227,42 +180,6 @@ public final class Interface {
public Optional<Integer> getMtu() {
return mtu;
}
public Optional<Integer> getJc() {
return jc;
}
public Optional<Integer> getJmin() {
return jmin;
}
public Optional<Integer> getJmax() {
return jmax;
}
public Optional<Integer> getS1() {
return s1;
}
public Optional<Integer> getS2() {
return s2;
}
public Optional<Long> getH1() {
return h1;
}
public Optional<Long> getH2() {
return h2;
}
public Optional<Long> getH3() {
return h3;
}
public Optional<Long> getH4() {
return h4;
}
@Override
public int hashCode() {
@@ -274,15 +191,6 @@ public final class Interface {
hash = 31 * hash + keyPair.hashCode();
hash = 31 * hash + listenPort.hashCode();
hash = 31 * hash + mtu.hashCode();
hash = 31 * hash + jc.hashCode();
hash = 31 * hash + jmin.hashCode();
hash = 31 * hash + jmax.hashCode();
hash = 31 * hash + s1.hashCode();
hash = 31 * hash + s2.hashCode();
hash = 31 * hash + h1.hashCode();
hash = 31 * hash + h2.hashCode();
hash = 31 * hash + h3.hashCode();
hash = 31 * hash + h4.hashCode();
return hash;
}
@@ -326,19 +234,6 @@ public final class Interface {
.append('\n');
listenPort.ifPresent(lp -> sb.append("ListenPort = ").append(lp).append('\n'));
mtu.ifPresent(m -> sb.append("MTU = ").append(m).append('\n'));
jc.ifPresent(t_jc -> sb.append("Jc = ").append(t_jc).append('\n'));
jmin.ifPresent(t_jmin -> sb.append("Jmin = ").append(t_jmin).append('\n'));
jmax.ifPresent(t_jmax -> sb.append("Jmax = ").append(t_jmax).append('\n'));
s1.ifPresent(t_s1 -> sb.append("S1 = ").append(t_s1).append('\n'));
s2.ifPresent(t_s2 -> sb.append("S2 = ").append(t_s2).append('\n'));
h1.ifPresent(t_h1 -> sb.append("H1 = ").append(t_h1).append('\n'));
h2.ifPresent(t_h2 -> sb.append("H2 = ").append(t_h2).append('\n'));
h3.ifPresent(t_h3 -> sb.append("H3 = ").append(t_h3).append('\n'));
h4.ifPresent(t_h4 -> sb.append("H4 = ").append(t_h4).append('\n'));
sb.append("PrivateKey = ").append(keyPair.getPrivateKey().toBase64()).append('\n');
return sb.toString();
}
@@ -353,18 +248,6 @@ public final class Interface {
final StringBuilder sb = new StringBuilder();
sb.append("private_key=").append(keyPair.getPrivateKey().toHex()).append('\n');
listenPort.ifPresent(lp -> sb.append("listen_port=").append(lp).append('\n'));
jc.ifPresent(t_jc -> sb.append("jc=").append(t_jc).append('\n'));
jmin.ifPresent(t_jmin -> sb.append("jmin=").append(t_jmin).append('\n'));
jmax.ifPresent(t_jmax -> sb.append("jmax=").append(t_jmax).append('\n'));
s1.ifPresent(t_s1 -> sb.append("s1=").append(t_s1).append('\n'));
s2.ifPresent(t_s2 -> sb.append("s2=").append(t_s2).append('\n'));
h1.ifPresent(t_h1 -> sb.append("h1=").append(t_h1).append('\n'));
h2.ifPresent(t_h2 -> sb.append("h2=").append(t_h2).append('\n'));
h3.ifPresent(t_h3 -> sb.append("h3=").append(t_h3).append('\n'));
h4.ifPresent(t_h4 -> sb.append("h4=").append(t_h4).append('\n'));
return sb.toString();
}
@@ -384,17 +267,6 @@ public final class Interface {
private Optional<Integer> listenPort = Optional.empty();
// Defaults to not present.
private Optional<Integer> mtu = Optional.empty();
private Optional<Integer> jc = Optional.empty();
private Optional<Integer> jmin = Optional.empty();
private Optional<Integer> jmax = Optional.empty();
private Optional<Integer> s1 = Optional.empty();
private Optional<Integer> s2 = Optional.empty();
private Optional<Long> h1 = Optional.empty();
private Optional<Long> h2 = Optional.empty();
private Optional<Long> h3 = Optional.empty();
private Optional<Long> h4 = Optional.empty();
public Builder addAddress(final InetNetwork address) {
addresses.add(address);
@@ -490,78 +362,6 @@ public final class Interface {
}
}
public Builder parseJc(final String jc) throws BadConfigException {
try {
return setJc(Integer.parseInt(jc));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.JC, jc, e);
}
}
public Builder parseJmax(final String jmax) throws BadConfigException {
try {
return setJmax(Integer.parseInt(jmax));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.JMAX, jmax, e);
}
}
public Builder parseJmin(final String jmin) throws BadConfigException {
try {
return setJmin(Integer.parseInt(jmin));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.JMIN, jmin, e);
}
}
public Builder parseS1(final String s1) throws BadConfigException {
try {
return setS1(Integer.parseInt(s1));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.S1, s1, e);
}
}
public Builder parseS2(final String s2) throws BadConfigException {
try {
return setS2(Integer.parseInt(s2));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.S2, s2, e);
}
}
public Builder parseH1(final String h1) throws BadConfigException {
try {
return setH1(Long.parseLong(h1));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.H1, h1, e);
}
}
public Builder parseH2(final String h2) throws BadConfigException {
try {
return setH2(Long.parseLong(h2));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.H2, h2, e);
}
}
public Builder parseH3(final String h3) throws BadConfigException {
try {
return setH3(Long.parseLong(h3));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.H3, h3, e);
}
}
public Builder parseH4(final String h4) throws BadConfigException {
try {
return setH4(Long.parseLong(h4));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.H4, h4, e);
}
}
public Builder parsePrivateKey(final String privateKey) throws BadConfigException {
try {
return setKeyPair(new KeyPair(Key.fromBase64(privateKey)));
@@ -586,81 +386,9 @@ public final class Interface {
public Builder setMtu(final int mtu) throws BadConfigException {
if (mtu < 0)
throw new BadConfigException(
Section.INTERFACE, Location.MTU, Reason.INVALID_VALUE, String.valueOf(mtu));
Section.INTERFACE, Location.LISTEN_PORT, Reason.INVALID_VALUE, String.valueOf(mtu));
this.mtu = mtu == 0 ? Optional.empty() : Optional.of(mtu);
return this;
}
public Builder setJc(final int jc) throws BadConfigException {
if (jc < 0)
throw new BadConfigException(
Section.INTERFACE, Location.JC, Reason.INVALID_VALUE, String.valueOf(jc));
this.jc = Optional.of(jc);
return this;
}
public Builder setJmin(final int jmin) throws BadConfigException {
if (jmin < 0)
throw new BadConfigException(
Section.INTERFACE, Location.JMIN, Reason.INVALID_VALUE, String.valueOf(jmin));
this.jmin = Optional.of(jmin);
return this;
}
public Builder setJmax(final int jmax) throws BadConfigException {
if (jmax < 0)
throw new BadConfigException(
Section.INTERFACE, Location.JMAX, Reason.INVALID_VALUE, String.valueOf(jmax));
this.jmax = Optional.of(jmax);
return this;
}
public Builder setS1(final int s1) throws BadConfigException {
if (s1 < 0)
throw new BadConfigException(
Section.INTERFACE, Location.S1, Reason.INVALID_VALUE, String.valueOf(s1));
this.s1 = Optional.of(s1);
return this;
}
public Builder setS2(final int s2) throws BadConfigException {
if (s2 < 0)
throw new BadConfigException(
Section.INTERFACE, Location.S2, Reason.INVALID_VALUE, String.valueOf(s2));
this.s2 = Optional.of(s2);
return this;
}
public Builder setH1(final long h1) throws BadConfigException {
if (h1 < 0)
throw new BadConfigException(
Section.INTERFACE, Location.H1, Reason.INVALID_VALUE, String.valueOf(h1));
this.h1 = Optional.of(h1);
return this;
}
public Builder setH2(final long h2) throws BadConfigException {
if (h2 < 0)
throw new BadConfigException(
Section.INTERFACE, Location.H2, Reason.INVALID_VALUE, String.valueOf(h2));
this.h2 = Optional.of(h2);
return this;
}
public Builder setH3(final long h3) throws BadConfigException {
if (h3 < 0)
throw new BadConfigException(
Section.INTERFACE, Location.H3, Reason.INVALID_VALUE, String.valueOf(h3));
this.h3 = Optional.of(h3);
return this;
}
public Builder setH4(final long h4) throws BadConfigException {
if (h4 < 0)
throw new BadConfigException(
Section.INTERFACE, Location.H4, Reason.INVALID_VALUE, String.valueOf(h4));
this.h4 = Optional.of(h4);
return this;
}
}
}
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright (C) 2014-2019 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package com.wireguard.config;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Utils
{
static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
/**
* Converts the given byte array to a hexadecimal string encoding.
*
* @param bytes byte array to convert
* @return hex string
*/
public static String bytesToHex(byte[] bytes)
{
char[] hex = new char[bytes.length * 2];
for (int i = 0; i < bytes.length; i++)
{
int value = bytes[i];
hex[i*2] = HEXDIGITS[(value & 0xf0) >> 4];
hex[i*2+1] = HEXDIGITS[ value & 0x0f];
}
return new String(hex);
}
/**
* Validate the given proposal string
*
* @param ike true for IKE, false for ESP
* @param proposal proposal string
* @return true if valid
*/
public native static boolean isProposalValid(boolean ike, String proposal);
/**
* Parse an IP address without doing a name lookup
*
* @param address IP address string
* @return address bytes if valid
*/
private native static byte[] parseInetAddressBytes(String address);
/**
* Parse an IP address without doing a name lookup (as compared to InetAddress.fromName())
*
* @param address IP address string
* @return address if valid
* @throws UnknownHostException if address is invalid
*/
public static InetAddress parseInetAddress(String address) throws UnknownHostException
{
byte[] bytes = parseInetAddressBytes(address);
if (bytes == null)
{
throw new UnknownHostException();
}
return InetAddress.getByAddress(bytes);
}
}

View File

@@ -16,8 +16,6 @@ import com.wireguard.crypto.Key
import org.json.JSONObject
import java.util.Base64
import com.wireguard.config.*
import net.openvpn.ovpn3.ClientAPI_Config
import net.openvpn.ovpn3.ClientAPI_EvalConfig
import net.openvpn.ovpn3.ClientAPI_Event
@@ -74,8 +72,6 @@ class OpenVPNThreadv3(var service: VPNService): ClientAPI_OpenVPNClient(), Runna
val jsonVpnConfig = mService.getVpnConfig()
val ovpnConfig = jsonVpnConfig.getJSONObject("openvpn_config_data").getString("config")
val splitTunnelType = jsonVpnConfig.getInt("splitTunnelType")
val splitTunnelSites = jsonVpnConfig.getJSONArray("splitTunnelSites")
val resultingConfig = StringBuilder()
resultingConfig.append(ovpnConfig)
@@ -119,7 +115,6 @@ class OpenVPNThreadv3(var service: VPNService): ClientAPI_OpenVPNClient(), Runna
eval_config(config)
val status = connect()
if (status.getError()) {
Log.i(tag, "connect() error: " + status.getError() + ": " + status.getMessage())
}
@@ -144,31 +139,6 @@ class OpenVPNThreadv3(var service: VPNService): ClientAPI_OpenVPNClient(), Runna
override fun tun_builder_establish(): Int {
Log.v(tag, "tun_builder_establish")
val jsonVpnConfig = mService.getVpnConfig()
val splitTunnelType = jsonVpnConfig.getInt("splitTunnelType")
val splitTunnelSites = jsonVpnConfig.getJSONArray("splitTunnelSites")
if (splitTunnelType == 1) {
for (i in 0 until splitTunnelSites.length()) {
val site = splitTunnelSites.getString(i)
val ipRange = IPRange(site)
mService.addRoute(ipRange.getFrom().getHostAddress(), ipRange.getPrefix())
}
}
if (splitTunnelType == 2) {
val ipRangeSet = IPRangeSet.fromString("0.0.0.0/0")
ipRangeSet.remove(IPRange("127.0.0.0/8"))
for (i in 0 until splitTunnelSites.length()) {
val site = splitTunnelSites.getString(i)
ipRangeSet.remove(IPRange(site))
}
ipRangeSet.subnets().forEach {
mService.addRoute(it.getFrom().getHostAddress(), it.getPrefix())
Thread.sleep(10)
}
mService.addRoute("2000::", 3)
}
return mService.establish()!!.detachFd()
}

View File

@@ -380,10 +380,7 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
mNetworkState.bindNetworkListener()
}
"wireguard" -> {
startWireGuard("wireguard")
}
"awg" -> {
startWireGuard("awg")
startWireGuard()
}
"shadowsocks" -> {
startShadowsocks()
@@ -460,8 +457,7 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
fun turnOff() {
Log.v(tag, "Aman: turnOff....................")
when (mProtocol) {
"wireguard",
"awg" -> {
"wireguard" -> {
GoBackend.wgTurnOff(currentTunnelHandle)
}
"cloak",
@@ -563,76 +559,37 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
}
return parseData
}
/**
* Create a Wireguard [Config] from a [json] string -
* The [json] will be created in AndroidVpnProtocol.cpp
*/
private fun buildWireguardConfig(obj: JSONObject, type: String): Config {
private fun buildWireguardConfig(obj: JSONObject): Config {
val confBuilder = Config.Builder()
val wireguardConfigData = obj.getJSONObject(type)
val splitTunnelType = obj.getInt("splitTunnelType")
val splitTunnelSites = obj.getJSONArray("splitTunnelSites")
val wireguardConfigData = obj.getJSONObject("wireguard_config_data")
val config = parseConfigData(wireguardConfigData.getString("config"))
val peerBuilder = Peer.Builder()
val peerConfig = config["Peer"]!!
peerBuilder.setPublicKey(Key.fromBase64(peerConfig["PublicKey"]))
peerConfig["PresharedKey"]?.let { peerBuilder.setPreSharedKey(Key.fromBase64(it)) }
val allIpString = peerConfig["AllowedIPs"]
var allowedIPList = peerConfig["AllowedIPs"]?.split(",") ?: emptyList()
/* default value in template */
if (allIpString == "0.0.0.0/0, ::/0") {
allowedIPList = emptyList()
peerConfig["PresharedKey"]?.let {
peerBuilder.setPreSharedKey(Key.fromBase64(it))
}
if (allowedIPList.isEmpty() && (splitTunnelType == 0)) {
/* AllowedIP is empty and splitTunnel is turnoff */
/* use VPN for whole Internet */
val internetV4 = InetNetwork.parse("0.0.0.0/0") // aka The whole internet.
peerBuilder.addAllowedIp(internetV4)
val internetV6 = InetNetwork.parse("::/0") // aka The whole internet.
peerBuilder.addAllowedIp(internetV6)
val allowedIPList = peerConfig["AllowedIPs"]?.split(",") ?: emptyList()
if (allowedIPList.isEmpty()) {
val internet = InetNetwork.parse("0.0.0.0/0") // aka The whole internet.
peerBuilder.addAllowedIp(internet)
} else {
if (!allowedIPList.isEmpty()) {
/* We have predefined AllowedIP in WG config */
/* It's have higher priority than system SplitTunnel */
allowedIPList.forEach {
val network = InetNetwork.parse(it.trim())
peerBuilder.addAllowedIp(network)
}
} else {
if (splitTunnelType == 1) {
/* Use system SplitTunnel */
/* VPN connection used only for defined IPs */
for (i in 0 until splitTunnelSites.length()) {
val site = splitTunnelSites.getString(i)
val internet = InetNetwork.parse(site)
peerBuilder.addAllowedIp(internet)
}
}
if (splitTunnelType == 2) {
/* Use system SplitTunnel */
/* VPN connection used for all Internet exclude defined IPs */
val ipRangeSet = IPRangeSet.fromString("0.0.0.0/0")
ipRangeSet.remove(IPRange("127.0.0.0/8"))
for (i in 0 until splitTunnelSites.length()) {
val site = splitTunnelSites.getString(i)
ipRangeSet.remove(IPRange(site))
}
val allowedIps = ipRangeSet.subnets().joinToString(", ") + ", 2000::/3"
peerBuilder.parseAllowedIPs(allowedIps)
}
allowedIPList.forEach {
val network = InetNetwork.parse(it.trim())
peerBuilder.addAllowedIp(network)
}
}
val endpointConfig = peerConfig["Endpoint"]
val endpoint = InetEndpoint.parse(endpointConfig)
peerBuilder.setEndpoint(endpoint)
peerConfig["PersistentKeepalive"]?.let { peerBuilder.setPersistentKeepalive(it.toInt()) }
peerConfig["PersistentKeepalive"]?.let {
peerBuilder.setPersistentKeepalive(it.toInt())
}
confBuilder.addPeer(peerBuilder.build())
val ifaceBuilder = Interface.Builder()
@@ -642,34 +599,11 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
ifaceConfig["DNS"]!!.split(",").forEach {
ifaceBuilder.addDnsServer(InetNetwork.parse(it.trim()).address)
}
ifaceBuilder.parsePrivateKey(ifaceConfig["PrivateKey"])
if (type == "awg_config_data") {
ifaceBuilder.parseJc(ifaceConfig["Jc"])
ifaceBuilder.parseJmin(ifaceConfig["Jmin"])
ifaceBuilder.parseJmax(ifaceConfig["Jmax"])
ifaceBuilder.parseS1(ifaceConfig["S1"])
ifaceBuilder.parseS2(ifaceConfig["S2"])
ifaceBuilder.parseH1(ifaceConfig["H1"])
ifaceBuilder.parseH2(ifaceConfig["H2"])
ifaceBuilder.parseH3(ifaceConfig["H3"])
ifaceBuilder.parseH4(ifaceConfig["H4"])
} else {
ifaceBuilder.parseJc("0")
ifaceBuilder.parseJmin("0")
ifaceBuilder.parseJmax("0")
ifaceBuilder.parseS1("0")
ifaceBuilder.parseS2("0")
ifaceBuilder.parseH1("0")
ifaceBuilder.parseH2("0")
ifaceBuilder.parseH3("0")
ifaceBuilder.parseH4("0")
}
/*val jExcludedApplication = obj.getJSONArray("excludedApps")
(0 until jExcludedApplication.length()).toList().forEach {
(0 until jExcludedApplication.length()).toList().forEach {
val appName = jExcludedApplication.get(it).toString()
ifaceBuilder.excludeApplication(appName)
}*/
}*/
confBuilder.setInterface(ifaceBuilder.build())
return confBuilder.build()
@@ -782,27 +716,21 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
}).start()
}
private fun startWireGuard(type: String) {
val wireguard_conf = buildWireguardConfig(mConfig!!, type + "_config_data")
private fun startWireGuard() {
val wireguard_conf = buildWireguardConfig(mConfig!!)
Log.i(tag, "startWireGuard: wireguard_conf : $wireguard_conf")
if (currentTunnelHandle != -1) {
Log.e(tag, "Tunnel already up")
// Turn the tunnel down because this might be a switch
GoBackend.wgTurnOff(currentTunnelHandle)
}
val wgConfig: String = wireguard_conf.toWgUserspaceString()
val builder = Builder()
setupBuilder(wireguard_conf, builder)
builder.setSession("Amnezia")
builder.establish().use { tun ->
if (tun == null) return
if (type == "awg"){
currentTunnelHandle = GoBackend.wgTurnOn("awg0", tun.detachFd(), wgConfig)
} else {
currentTunnelHandle = GoBackend.wgTurnOn("amn0", tun.detachFd(), wgConfig)
}
if (tun == null) return
currentTunnelHandle = GoBackend.wgTurnOn("Amnezia", tun.detachFd(), wgConfig)
}
if (currentTunnelHandle < 0) {
Log.e(tag, "Activation Error Code -> $currentTunnelHandle")

View File

@@ -97,7 +97,7 @@ target_compile_options(${PROJECT} PRIVATE
-DVPN_NE_BUNDLEID=\"${BUILD_IOS_APP_IDENTIFIER}.network-extension\"
)
set(WG_APPLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd/awg-apple/Sources)
set(WG_APPLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd/wireguard-apple/Sources)
target_sources(${PROJECT} PRIVATE
# ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosvpnprotocol.swift

View File

@@ -1,46 +0,0 @@
#include "awg_configurator.h"
#include <QJsonDocument>
#include <QJsonObject>
#include "core/servercontroller.h"
AwgConfigurator::AwgConfigurator(std::shared_ptr<Settings> settings, QObject *parent)
: WireguardConfigurator(settings, true, parent)
{
}
QString AwgConfigurator::genAwgConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode)
{
QString config = WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, clientId, errorCode);
QJsonObject jsonConfig = QJsonDocument::fromJson(config.toUtf8()).object();
QString awgConfig = jsonConfig.value(config_key::config).toString();
QMap<QString, QString> configMap;
auto configLines = awgConfig.split("\n");
for (auto &line : configLines) {
auto trimmedLine = line.trimmed();
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
continue;
} else {
QStringList parts = trimmedLine.split(" = ");
if (parts.count() == 2) {
configMap.insert(parts[0].trimmed(), parts[1].trimmed());
}
}
}
jsonConfig[config_key::junkPacketCount] = configMap.value(config_key::junkPacketCount);
jsonConfig[config_key::junkPacketMinSize] = configMap.value(config_key::junkPacketMinSize);
jsonConfig[config_key::junkPacketMaxSize] = configMap.value(config_key::junkPacketMaxSize);
jsonConfig[config_key::initPacketJunkSize] = configMap.value(config_key::initPacketJunkSize);
jsonConfig[config_key::responsePacketJunkSize] = configMap.value(config_key::responsePacketJunkSize);
jsonConfig[config_key::initPacketMagicHeader] = configMap.value(config_key::initPacketMagicHeader);
jsonConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader);
jsonConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader);
jsonConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader);
return QJsonDocument(jsonConfig).toJson();
}

View File

@@ -1,18 +0,0 @@
#ifndef AWGCONFIGURATOR_H
#define AWGCONFIGURATOR_H
#include <QObject>
#include "wireguard_configurator.h"
class AwgConfigurator : public WireguardConfigurator
{
Q_OBJECT
public:
AwgConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genAwgConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr);
};
#endif // AWGCONFIGURATOR_H

View File

@@ -83,7 +83,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co
}
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode)
const QJsonObject &containerConfig, ErrorCode *errorCode)
{
ServerController serverController(m_settings);
QString config =
@@ -113,8 +113,6 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
QJsonObject jConfig;
jConfig[config_key::config] = config;
clientId = connData.clientId;
return QJsonDocument(jConfig).toJson();
}
@@ -133,13 +131,10 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig)
config.append("block-ipv6\n");
}
if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
// no redirect-gateway
}
if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
#ifndef Q_OS_ANDROID
config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n");
#endif
// Prevent ipv6 leak
config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n");
config.append("block-ipv6\n");

View File

@@ -24,7 +24,7 @@ public:
};
QString genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr);
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
QString processConfigWithLocalSettings(QString jsonConfig);
QString processConfigWithExportSettings(QString jsonConfig);

View File

@@ -1,53 +1,51 @@
#include "vpn_configurator.h"
#include "cloak_configurator.h"
#include "ikev2_configurator.h"
#include "openvpn_configurator.h"
#include "cloak_configurator.h"
#include "shadowsocks_configurator.h"
#include "ssh_configurator.h"
#include "wireguard_configurator.h"
#include "awg_configurator.h"
#include "ikev2_configurator.h"
#include "ssh_configurator.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonDocument>
#include "containers/containers_defs.h"
#include "settings.h"
#include "utilities.h"
#include "settings.h"
VpnConfigurator::VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent)
: ConfiguratorBase(settings, parent)
VpnConfigurator::VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
{
openVpnConfigurator = std::shared_ptr<OpenVpnConfigurator>(new OpenVpnConfigurator(settings, this));
shadowSocksConfigurator = std::shared_ptr<ShadowSocksConfigurator>(new ShadowSocksConfigurator(settings, this));
cloakConfigurator = std::shared_ptr<CloakConfigurator>(new CloakConfigurator(settings, this));
wireguardConfigurator = std::shared_ptr<WireguardConfigurator>(new WireguardConfigurator(settings, false, this));
wireguardConfigurator = std::shared_ptr<WireguardConfigurator>(new WireguardConfigurator(settings, this));
ikev2Configurator = std::shared_ptr<Ikev2Configurator>(new Ikev2Configurator(settings, this));
sshConfigurator = std::shared_ptr<SshConfigurator>(new SshConfigurator(settings, this));
awgConfigurator = std::shared_ptr<AwgConfigurator>(new AwgConfigurator(settings, this));
}
QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, Proto proto, QString &clientId, ErrorCode *errorCode)
QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode)
{
switch (proto) {
case Proto::OpenVpn:
return openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, clientId, errorCode);
return openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, errorCode);
case Proto::ShadowSocks:
return shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, errorCode);
case Proto::Cloak: return cloakConfigurator->genCloakConfig(credentials, container, containerConfig, errorCode);
case Proto::Cloak:
return cloakConfigurator->genCloakConfig(credentials, container, containerConfig, errorCode);
case Proto::WireGuard:
return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, clientId, errorCode);
return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, errorCode);
case Proto::Awg:
return awgConfigurator->genAwgConfig(credentials, container, containerConfig, clientId, errorCode);
case Proto::Ikev2:
return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode);
case Proto::Ikev2: return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode);
default: return "";
default:
return "";
}
}
@@ -64,8 +62,8 @@ QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
if (dns.first.isEmpty() || !Utils::checkIPv4Format(dns.first)) {
if (useAmneziaDns && m_settings->containers(serverIndex).contains(DockerContainer::Dns)) {
dns.first = protocols::dns::amneziaDnsIp;
} else
dns.first = m_settings->primaryDns();
}
else dns.first = m_settings->primaryDns();
}
if (dns.second.isEmpty() || !Utils::checkIPv4Format(dns.second)) {
dns.second = m_settings->secondaryDns();
@@ -75,8 +73,8 @@ QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
return dns;
}
QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto,
QString &config)
QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerContainer container,
Proto proto, QString &config)
{
auto dns = getDnsForConfig(serverIndex);
@@ -86,8 +84,8 @@ QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerCo
return config;
}
QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto,
QString &config)
QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, DockerContainer container,
Proto proto, QString &config)
{
processConfigWithDnsSettings(serverIndex, container, proto, config);
@@ -97,8 +95,8 @@ QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, Docker
return config;
}
QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto,
QString &config)
QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, DockerContainer container,
Proto proto, QString &config)
{
processConfigWithDnsSettings(serverIndex, container, proto, config);
@@ -109,7 +107,7 @@ QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, Docke
}
void VpnConfigurator::updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig,
const QString &stdOut)
const QString &stdOut)
{
Proto mainProto = ContainerProps::defaultProtocol(container);

View File

@@ -6,24 +6,23 @@
#include "configurator_base.h"
#include "core/defs.h"
class OpenVpnConfigurator;
class ShadowSocksConfigurator;
class CloakConfigurator;
class WireguardConfigurator;
class Ikev2Configurator;
class SshConfigurator;
class AwgConfigurator;
// Retrieve connection settings from server
class VpnConfigurator : public ConfiguratorBase
class VpnConfigurator : ConfiguratorBase
{
Q_OBJECT
public:
explicit VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, Proto proto, QString &clientId,
ErrorCode *errorCode = nullptr);
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr);
QPair<QString, QString> getDnsForConfig(int serverIndex);
QString &processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
@@ -32,8 +31,8 @@ public:
QString &processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
// workaround for containers which is not support normal configuration
void updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig,
const QString &stdOut);
void updateContainerConfigAfterInstallation(DockerContainer container,
QJsonObject &containerConfig, const QString &stdOut);
std::shared_ptr<OpenVpnConfigurator> openVpnConfigurator;
std::shared_ptr<ShadowSocksConfigurator> shadowSocksConfigurator;
@@ -41,11 +40,6 @@ public:
std::shared_ptr<WireguardConfigurator> wireguardConfigurator;
std::shared_ptr<Ikev2Configurator> ikev2Configurator;
std::shared_ptr<SshConfigurator> sshConfigurator;
std::shared_ptr<AwgConfigurator> awgConfigurator;
signals:
void newVpnConfigCreated(const QString &clientId, const QString &clientName, const DockerContainer container,
ServerCredentials credentials);
};
#endif // VPN_CONFIGURATOR_H

View File

@@ -19,20 +19,9 @@
#include "settings.h"
#include "utilities.h"
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, bool isAwg, QObject *parent)
: ConfiguratorBase(settings, parent), m_isAwg(isAwg)
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, QObject *parent)
: ConfiguratorBase(settings, parent)
{
m_serverConfigPath = m_isAwg ? amnezia::protocols::awg::serverConfigPath
: amnezia::protocols::wireguard::serverConfigPath;
m_serverPublicKeyPath = m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath
: amnezia::protocols::wireguard::serverPublicKeyPath;
m_serverPskKeyPath = m_isAwg ? amnezia::protocols::awg::serverPskKeyPath
: amnezia::protocols::wireguard::serverPskKeyPath;
m_configTemplate = m_isAwg ? ProtocolScriptType::awg_template
: ProtocolScriptType::wireguard_template;
m_protocolName = m_isAwg ? config_key::awg : config_key::wireguard;
m_defaultPort = m_isAwg ? protocols::wireguard::defaultPort : protocols::awg::defaultPort;
}
WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
@@ -73,7 +62,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
{
WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys();
connData.host = credentials.hostName;
connData.port = containerConfig.value(m_protocolName).toObject().value(config_key::port).toString(m_defaultPort);
connData.port = containerConfig.value(config_key::port).toString(protocols::wireguard::defaultPort);
if (connData.clientPrivKey.isEmpty() || connData.clientPubKey.isEmpty()) {
if (errorCode)
@@ -87,7 +76,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
// Get list of already created clients (only IP addresses)
QString nextIpNumber;
{
QString script = QString("cat %1 | grep AllowedIPs").arg(m_serverConfigPath);
QString script = QString("cat %1 | grep AllowedIPs").arg(amnezia::protocols::wireguard::serverConfigPath);
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
@@ -134,7 +123,8 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
}
// Get keys
connData.serverPubKey = serverController.getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, &e);
connData.serverPubKey = serverController.getTextFileFromContainer(
container, credentials, amnezia::protocols::wireguard::serverPublicKeyPath, &e);
connData.serverPubKey.replace("\n", "");
if (e) {
if (errorCode)
@@ -142,7 +132,8 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
return connData;
}
connData.pskKey = serverController.getTextFileFromContainer(container, credentials, m_serverPskKeyPath, &e);
connData.pskKey = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::wireguard::serverPskKeyPath, &e);
connData.pskKey.replace("\n", "");
if (e) {
@@ -156,9 +147,12 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
"PublicKey = %1\n"
"PresharedKey = %2\n"
"AllowedIPs = %3/32\n\n")
.arg(connData.clientPubKey, connData.pskKey, connData.clientIP);
.arg(connData.clientPubKey)
.arg(connData.pskKey)
.arg(connData.clientIP);
e = serverController.uploadTextFileToContainer(container, credentials, configPart, m_serverConfigPath,
e = serverController.uploadTextFileToContainer(container, credentials, configPart,
protocols::wireguard::serverConfigPath,
libssh::SftpOverwriteMode::SftpAppendToExisting);
if (e) {
@@ -167,22 +161,22 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
return connData;
}
QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'")
.arg(m_serverConfigPath);
e = serverController.runScript(
credentials, serverController.replaceVars(script, serverController.genVarsForScript(credentials, container)));
credentials,
serverController.replaceVars("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick "
"strip /opt/amnezia/wireguard/wg0.conf)'",
serverController.genVarsForScript(credentials, container)));
return connData;
}
QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode)
const QJsonObject &containerConfig, ErrorCode *errorCode)
{
ServerController serverController(m_settings);
QString scriptData = amnezia::scriptData(m_configTemplate, container);
QString config = serverController.replaceVars(
scriptData, serverController.genVarsForScript(credentials, container, containerConfig));
QString config =
serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::wireguard_template, container),
serverController.genVarsForScript(credentials, container, containerConfig));
ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode);
if (errorCode && *errorCode) {
@@ -205,8 +199,6 @@ QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &crede
jConfig[config_key::psk_key] = connData.pskKey;
jConfig[config_key::server_pub_key] = connData.serverPubKey;
clientId = connData.clientPubKey;
return QJsonDocument(jConfig).toJson();
}

View File

@@ -6,44 +6,35 @@
#include "configurator_base.h"
#include "core/defs.h"
#include "core/scripts_registry.h"
class WireguardConfigurator : public ConfiguratorBase
class WireguardConfigurator : ConfiguratorBase
{
Q_OBJECT
public:
WireguardConfigurator(std::shared_ptr<Settings> settings, bool isAwg, QObject *parent = nullptr);
WireguardConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
struct ConnectionData
{
struct ConnectionData {
QString clientPrivKey; // client private key
QString clientPubKey; // client public key
QString clientIP; // internal client IP address
QString serverPubKey; // tls-auth key
QString pskKey; // preshared key
QString host; // host ip
QString clientPubKey; // client public key
QString clientIP; // internal client IP address
QString serverPubKey; // tls-auth key
QString pskKey; // preshared key
QString host; // host ip
QString port;
};
QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr);
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
QString processConfigWithLocalSettings(QString config);
QString processConfigWithExportSettings(QString config);
private:
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
ConnectionData genClientKeys();
bool m_isAwg;
QString m_serverConfigPath;
QString m_serverPublicKeyPath;
QString m_serverPskKeyPath;
amnezia::ProtocolScriptType m_configTemplate;
QString m_protocolName;
QString m_defaultPort;
};
#endif // WIREGUARD_CONFIGURATOR_H

View File

@@ -84,11 +84,11 @@ QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
{ DockerContainer::ShadowSocks, "ShadowSocks" },
{ DockerContainer::Cloak, "OpenVPN over Cloak" },
{ DockerContainer::WireGuard, "WireGuard" },
{ DockerContainer::Awg, "AmneziaWG" },
{ DockerContainer::Ipsec, QObject::tr("IPsec") },
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
{ DockerContainer::Dns, QObject::tr("Amnezia DNS") },
//{DockerContainer::FileShare, QObject::tr("SMB file sharing service")},
{ DockerContainer::Sftp, QObject::tr("Sftp file sharing service") } };
}
@@ -107,10 +107,6 @@ QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
{ DockerContainer::WireGuard,
QObject::tr("WireGuard - New popular VPN protocol with high performance, high speed and low power "
"consumption. Recommended for regions with low levels of censorship.") },
{ DockerContainer::Awg,
QObject::tr("AmneziaWG - Special protocol from Amnezia, based on WireGuard. It's fast like WireGuard, "
"but very resistant to blockages. "
"Recommended for regions with high levels of censorship.") },
{ DockerContainer::Ipsec,
QObject::tr("IKEv2 - Modern stable protocol, a bit faster than others, restores connection after "
"signal loss. It has native support on the latest versions of Android and iOS.") },
@@ -118,108 +114,42 @@ QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
{ DockerContainer::TorWebSite, QObject::tr("Deploy a WordPress site on the Tor network in two clicks.") },
{ DockerContainer::Dns,
QObject::tr("Replace the current DNS server with your own. This will increase your privacy level.") },
//{DockerContainer::FileShare, QObject::tr("SMB file sharing service - is Window file sharing protocol")},
{ DockerContainer::Sftp,
QObject::tr("Creates a file vault on your server to securely store and transfer files.") } };
}
QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
{
return {
{ DockerContainer::OpenVpn,
QObject::tr(
"OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
"It employs its unique security protocol, "
"leveraging the strength of SSL/TLS for encryption and key exchange. "
"Furthermore, OpenVPN's support for a multitude of authentication methods makes it versatile and adaptable, "
"catering to a wide range of devices and operating systems. "
"Due to its open-source nature, OpenVPN benefits from extensive scrutiny by the global community, "
"which continually reinforces its security. "
"With a strong balance of performance, security, and compatibility, "
"OpenVPN remains a top choice for privacy-conscious individuals and businesses alike.\n\n"
"* Available in the AmneziaVPN across all platforms\n"
"* Normal power consumption on mobile devices\n"
"* Flexible customisation to suit user needs to work with different operating systems and devices\n"
"* Recognised by DPI analysis systems and therefore susceptible to blocking\n"
"* Can operate over both TCP and UDP network protocols.") },
{ DockerContainer::ShadowSocks,
QObject::tr("Shadowsocks, inspired by the SOCKS5 protocol, safeguards the connection using the AEAD cipher. "
"Although Shadowsocks is designed to be discreet and challenging to identify, it isn't identical to a standard HTTPS connection."
"However, certain traffic analysis systems might still detect a Shadowsocks connection. "
"Due to limited support in Amnezia, it's recommended to use AmneziaWG protocol.\n\n"
"* Available in the AmneziaVPN only on desktop platforms\n"
"* Normal power consumption on mobile devices\n\n"
"* Configurable encryption protocol\n"
"* Detectable by some DPI systems\n"
"* Works over TCP network protocol.") },
{ DockerContainer::Cloak,
QObject::tr("This is a combination of the OpenVPN protocol and the Cloak plugin designed specifically for "
"blocking protection.\n\n"
"OpenVPN provides a secure VPN connection by encrypting all Internet traffic between the client "
"and the server.\n\n"
"Cloak protects OpenVPN from detection and blocking. \n\n"
"Cloak can modify packet metadata so that it completely masks VPN traffic as normal web traffic, "
"and also protects the VPN from detection by Active Probing. This makes it very resistant to "
"being detected\n\n"
"Immediately after receiving the first data packet, Cloak authenticates the incoming connection. "
"If authentication fails, the plugin masks the server as a fake website and your VPN becomes "
"invisible to analysis systems.\n\n"
"If there is a extreme level of Internet censorship in your region, we advise you to use only "
"OpenVPN over Cloak from the first connection\n\n"
"* Available in the AmneziaVPN across all platforms\n"
"* High power consumption on mobile devices\n"
"* Flexible settings\n"
"* Not recognised by DPI analysis systems\n"
"* Works over TCP network protocol, 443 port.\n") },
{ DockerContainer::WireGuard,
QObject::tr("A relatively new popular VPN protocol with a simplified architecture.\n"
"Provides stable VPN connection, high performance on all devices. Uses hard-coded encryption "
"settings. WireGuard compared to OpenVPN has lower latency and better data transfer throughput.\n"
"WireGuard is very susceptible to blocking due to its distinct packet signatures. "
"Unlike some other VPN protocols that employ obfuscation techniques, "
"the consistent signature patterns of WireGuard packets can be more easily identified and "
"thus blocked by advanced Deep Packet Inspection (DPI) systems and other network monitoring tools.\n\n"
"* Available in the AmneziaVPN across all platforms\n"
"* Low power consumption\n"
"* Minimum number of settings\n"
"* Easily recognised by DPI analysis systems, susceptible to blocking\n"
"* Works over UDP network protocol.") },
{ DockerContainer::Awg,
QObject::tr("A modern iteration of the popular VPN protocol, "
"AmneziaWG builds upon the foundation set by WireGuard, "
"retaining its simplified architecture and high-performance capabilities across devices.\n"
"While WireGuard is known for its efficiency, "
"it had issues with being easily detected due to its distinct packet signatures. "
"AmneziaWG solves this problem by using better obfuscation methods, "
"making its traffic blend in with regular internet traffic.\n"
"This means that AmneziaWG keeps the fast performance of the original "
"while adding an extra layer of stealth, "
"making it a great choice for those wanting a fast and discreet VPN connection.\n\n"
"* Available in the AmneziaVPN across all platforms\n"
"* Low power consumption\n"
"* Minimum number of settings\n"
"* Not recognised by DPI analysis systems, resistant to blocking\n"
"* Works over UDP network protocol.") },
{ DockerContainer::Ipsec,
QObject::tr("IKEv2, paired with the IPSec encryption layer, stands as a modern and stable VPN protocol.\n"
"One of its distinguishing features is its ability to swiftly switch between networks and devices, "
"making it particularly adaptive in dynamic network environments. \n"
"While it offers a blend of security, stability, and speed, "
"it's essential to note that IKEv2 can be easily detected and is susceptible to blocking.\n\n"
"* Available in the AmneziaVPN only on Windows\n"
"* Low power consumption, on mobile devices\n"
"* Minimal configuration\n"
"* Recognised by DPI analysis systems\n"
"* Works over UDP network protocol, ports 500 and 4500.") },
return { { DockerContainer::OpenVpn, QObject::tr("OpenVPN container") },
{ DockerContainer::ShadowSocks, QObject::tr("Container with OpenVpn and ShadowSocks") },
{ DockerContainer::Cloak,
QObject::tr("Container with OpenVpn and ShadowSocks protocols "
"configured with traffic masking by Cloak plugin") },
{ DockerContainer::WireGuard, QObject::tr("WireGuard container") },
{ DockerContainer::Ipsec, QObject::tr("IPsec container") },
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
{ DockerContainer::Dns, QObject::tr("DNS Service") },
{ DockerContainer::Sftp, QObject::tr("Sftp file sharing service - is secure FTP service") }
};
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
{ DockerContainer::Dns, QObject::tr("DNS Service") },
//{DockerContainer::FileShare, QObject::tr("SMB file sharing service - is Window file sharing protocol")},
{ DockerContainer::Sftp, QObject::tr("Sftp file sharing service - is secure FTP service") } };
}
amnezia::ServiceType ContainerProps::containerService(DockerContainer c)
{
return ProtocolProps::protocolService(defaultProtocol(c));
switch (c) {
case DockerContainer::None: return ServiceType::None;
case DockerContainer::OpenVpn: return ServiceType::Vpn;
case DockerContainer::Cloak: return ServiceType::Vpn;
case DockerContainer::ShadowSocks: return ServiceType::Vpn;
case DockerContainer::WireGuard: return ServiceType::Vpn;
case DockerContainer::Ipsec: return ServiceType::Vpn;
case DockerContainer::TorWebSite: return ServiceType::Other;
case DockerContainer::Dns: return ServiceType::Other;
// case DockerContainer::FileShare : return ServiceType::Other;
case DockerContainer::Sftp: return ServiceType::Other;
default: return ServiceType::Other;
}
}
Proto ContainerProps::defaultProtocol(DockerContainer c)
@@ -230,11 +160,11 @@ Proto ContainerProps::defaultProtocol(DockerContainer c)
case DockerContainer::Cloak: return Proto::Cloak;
case DockerContainer::ShadowSocks: return Proto::ShadowSocks;
case DockerContainer::WireGuard: return Proto::WireGuard;
case DockerContainer::Awg: return Proto::Awg;
case DockerContainer::Ipsec: return Proto::Ikev2;
case DockerContainer::TorWebSite: return Proto::TorWebSite;
case DockerContainer::Dns: return Proto::Dns;
// case DockerContainer::FileShare : return Protocol::FileShare;
case DockerContainer::Sftp: return Proto::Sftp;
default: return Proto::Any;
}
@@ -249,7 +179,6 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
switch (c) {
case DockerContainer::WireGuard: return true;
case DockerContainer::OpenVpn: return true;
case DockerContainer::Awg: return true;
case DockerContainer::Cloak:
return true;
// case DockerContainer::ShadowSocks: return true;
@@ -267,7 +196,6 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
case DockerContainer::WireGuard: return true;
case DockerContainer::OpenVpn: return true;
case DockerContainer::ShadowSocks: return true;
case DockerContainer::Awg: return true;
case DockerContainer::Cloak: return true;
default: return false;
}
@@ -296,8 +224,8 @@ bool ContainerProps::isEasySetupContainer(DockerContainer container)
{
switch (container) {
case DockerContainer::WireGuard: return true;
case DockerContainer::Awg: return true;
case DockerContainer::Cloak: return true;
case DockerContainer::OpenVpn: return true;
default: return false;
}
}
@@ -306,8 +234,8 @@ QString ContainerProps::easySetupHeader(DockerContainer container)
{
switch (container) {
case DockerContainer::WireGuard: return tr("Low");
case DockerContainer::Awg: return tr("Medium or High");
case DockerContainer::Cloak: return tr("Extreme");
case DockerContainer::Cloak: return tr("High");
case DockerContainer::OpenVpn: return tr("Medium");
default: return "";
}
}
@@ -315,10 +243,9 @@ QString ContainerProps::easySetupHeader(DockerContainer container)
QString ContainerProps::easySetupDescription(DockerContainer container)
{
switch (container) {
case DockerContainer::WireGuard: return tr("I just want to increase the level of my privacy.");
case DockerContainer::Awg: return tr("I want to bypass censorship. This option recommended in most cases.");
case DockerContainer::Cloak:
return tr("Most VPN protocols are blocked. Recommended if other options are not working.");
case DockerContainer::WireGuard: return tr("I just want to increase the level of privacy");
case DockerContainer::Cloak: return tr("Many foreign websites and VPN providers are blocked");
case DockerContainer::OpenVpn: return tr("Some foreign sites are blocked, but VPN providers are not blocked");
default: return "";
}
}
@@ -326,9 +253,9 @@ QString ContainerProps::easySetupDescription(DockerContainer container)
int ContainerProps::easySetupOrder(DockerContainer container)
{
switch (container) {
case DockerContainer::WireGuard: return 3;
case DockerContainer::Awg: return 2;
case DockerContainer::Cloak: return 1;
case DockerContainer::WireGuard: return 1;
case DockerContainer::Cloak: return 3;
case DockerContainer::OpenVpn: return 2;
default: return 0;
}
}

View File

@@ -16,16 +16,16 @@ namespace amnezia
Q_NAMESPACE
enum DockerContainer {
None = 0,
Awg,
WireGuard,
OpenVpn,
Cloak,
ShadowSocks,
Cloak,
WireGuard,
Ipsec,
// non-vpn
TorWebSite,
Dns,
// FileShare,
Sftp
};
Q_ENUM_NS(DockerContainer)

View File

@@ -36,7 +36,7 @@ enum ErrorCode
ServerPacketManagerError,
// Ssh connection errors
SshRequestDeniedError, SshInterruptedError, SshInternalError,
SshRequsetDeniedError, SshInterruptedError, SshInternalError,
SshPrivateKeyError, SshPrivateKeyFormatError, SshTimeoutError,
// Ssh sftp errors
@@ -47,6 +47,7 @@ enum ErrorCode
SshSftpNoMediaError,
// Local errors
FailedToSaveConfigData,
OpenVpnConfigMissing,
OpenVpnManagementServerError,
ConfigMissing,
@@ -66,6 +67,7 @@ enum ErrorCode
// 3rd party utils errors
OpenSslFailed,
OpenVpnExecutableCrashed,
ShadowSocksExecutableCrashed,
CloakExecutableCrashed,

View File

@@ -19,7 +19,7 @@ QString errorString(ErrorCode code){
case(ServerUserNotInSudo): return QObject::tr("The user does not have permission to use sudo");
// Libssh errors
case(SshRequestDeniedError): return QObject::tr("Ssh request was denied");
case(SshRequsetDeniedError): return QObject::tr("Ssh request was denied");
case(SshInterruptedError): return QObject::tr("Ssh request was interrupted");
case(SshInternalError): return QObject::tr("Ssh internal error");
case(SshPrivateKeyError): return QObject::tr("Invalid private key or invalid passphrase entered");
@@ -42,6 +42,7 @@ QString errorString(ErrorCode code){
case(SshSftpNoMediaError): return QObject::tr("Sftp error: No media was in remote drive");
// Local errors
case (FailedToSaveConfigData): return QObject::tr("Failed to save config to disk");
case (OpenVpnConfigMissing): return QObject::tr("OpenVPN config missing");
case (OpenVpnManagementServerError): return QObject::tr("OpenVPN management server error");

View File

@@ -1,8 +1,8 @@
#include "scripts_registry.h"
#include <QObject>
#include <QDebug>
#include <QFile>
#include <QObject>
QString amnezia::scriptFolder(amnezia::DockerContainer container)
{
@@ -11,11 +11,11 @@ QString amnezia::scriptFolder(amnezia::DockerContainer container)
case DockerContainer::Cloak: return QLatin1String("openvpn_cloak");
case DockerContainer::ShadowSocks: return QLatin1String("openvpn_shadowsocks");
case DockerContainer::WireGuard: return QLatin1String("wireguard");
case DockerContainer::Awg: return QLatin1String("awg");
case DockerContainer::Ipsec: return QLatin1String("ipsec");
case DockerContainer::TorWebSite: return QLatin1String("website_tor");
case DockerContainer::Dns: return QLatin1String("dns");
//case DockerContainer::FileShare: return QLatin1String("file_share");
case DockerContainer::Sftp: return QLatin1String("sftp");
default: return "";
}
@@ -45,7 +45,6 @@ QString amnezia::scriptName(ProtocolScriptType type)
case ProtocolScriptType::container_startup: return QLatin1String("start.sh");
case ProtocolScriptType::openvpn_template: return QLatin1String("template.ovpn");
case ProtocolScriptType::wireguard_template: return QLatin1String("template.conf");
case ProtocolScriptType::awg_template: return QLatin1String("template.conf");
}
}
@@ -53,7 +52,7 @@ QString amnezia::scriptData(amnezia::SharedScriptType type)
{
QString fileName = QString(":/server_scripts/%1").arg(amnezia::scriptName(type));
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
if (! file.open(QIODevice::ReadOnly)) {
qDebug() << "Warning: script missing" << fileName;
return "";
}
@@ -68,7 +67,7 @@ QString amnezia::scriptData(amnezia::ProtocolScriptType type, DockerContainer co
{
QString fileName = QString(":/server_scripts/%1/%2").arg(amnezia::scriptFolder(container), amnezia::scriptName(type));
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
if (! file.open(QIODevice::ReadOnly)) {
qDebug() << "Warning: script missing" << fileName;
return "";
}

View File

@@ -26,8 +26,7 @@ enum ProtocolScriptType {
configure_container,
container_startup,
openvpn_template,
wireguard_template,
awg_template
wireguard_template
};

View File

@@ -167,8 +167,11 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
return ErrorCode::ServerContainerMissingError;
}
runScript(credentials,
replaceVars(QString("sudo shred -u %1").arg(tmpFileName), genVarsForScript(credentials, container)));
runScript(credentials,
replaceVars(QString("sudo shred %1").arg(tmpFileName), genVarsForScript(credentials, container)));
runScript(credentials, replaceVars(QString("sudo rm %1").arg(tmpFileName), genVarsForScript(credentials, container)));
return e;
}
@@ -335,10 +338,6 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
return true;
}
if (container == DockerContainer::Awg) {
return true;
}
return false;
}
@@ -487,7 +486,6 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
const QJsonObject &cloakConfig = config.value(ProtocolProps::protoToString(Proto::Cloak)).toObject();
const QJsonObject &ssConfig = config.value(ProtocolProps::protoToString(Proto::ShadowSocks)).toObject();
const QJsonObject &wireguarConfig = config.value(ProtocolProps::protoToString(Proto::WireGuard)).toObject();
const QJsonObject &amneziaWireguarConfig = config.value(ProtocolProps::protoToString(Proto::Awg)).toObject();
const QJsonObject &sftpConfig = config.value(ProtocolProps::protoToString(Proto::Sftp)).toObject();
Vars vars;
@@ -584,25 +582,6 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
vars.append({ { "$SFTP_USER", sftpConfig.value(config_key::userName).toString() } });
vars.append({ { "$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() } });
// Amnezia wireguard vars
vars.append({ { "$AWG_SERVER_PORT",
amneziaWireguarConfig.value(config_key::port).toString(protocols::awg::defaultPort) } });
vars.append({ { "$JUNK_PACKET_COUNT", amneziaWireguarConfig.value(config_key::junkPacketCount).toString() } });
vars.append({ { "$JUNK_PACKET_MIN_SIZE", amneziaWireguarConfig.value(config_key::junkPacketMinSize).toString() } });
vars.append({ { "$JUNK_PACKET_MAX_SIZE", amneziaWireguarConfig.value(config_key::junkPacketMaxSize).toString() } });
vars.append({ { "$INIT_PACKET_JUNK_SIZE", amneziaWireguarConfig.value(config_key::initPacketJunkSize).toString() } });
vars.append({ { "$RESPONSE_PACKET_JUNK_SIZE",
amneziaWireguarConfig.value(config_key::responsePacketJunkSize).toString() } });
vars.append({ { "$INIT_PACKET_MAGIC_HEADER",
amneziaWireguarConfig.value(config_key::initPacketMagicHeader).toString() } });
vars.append({ { "$RESPONSE_PACKET_MAGIC_HEADER",
amneziaWireguarConfig.value(config_key::responsePacketMagicHeader).toString() } });
vars.append({ { "$UNDERLOAD_PACKET_MAGIC_HEADER",
amneziaWireguarConfig.value(config_key::underloadPacketMagicHeader).toString() } });
vars.append({ { "$TRANSPORT_PACKET_MAGIC_HEADER",
amneziaWireguarConfig.value(config_key::transportPacketMagicHeader).toString() } });
QString serverIp = Utils::getIPAddress(credentials.hostName);
if (!serverIp.isEmpty()) {
vars.append({ { "$SERVER_IP_ADDRESS", serverIp } });
@@ -831,34 +810,6 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential
containerConfig.insert(config_key::port, port);
containerConfig.insert(config_key::transport_proto, transportProto);
if (protocol == Proto::Awg) {
QString serverConfig = getTextFileFromContainer(container, credentials, protocols::awg::serverConfigPath, &errorCode);
QMap<QString, QString> serverConfigMap;
auto serverConfigLines = serverConfig.split("\n");
for (auto &line : serverConfigLines) {
auto trimmedLine = line.trimmed();
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
continue;
} else {
QStringList parts = trimmedLine.split(" = ");
if (parts.count() == 2) {
serverConfigMap.insert(parts[0].trimmed(), parts[1].trimmed());
}
}
}
containerConfig[config_key::junkPacketCount] = serverConfigMap.value(config_key::junkPacketCount);
containerConfig[config_key::junkPacketMinSize] = serverConfigMap.value(config_key::junkPacketMinSize);
containerConfig[config_key::junkPacketMaxSize] = serverConfigMap.value(config_key::junkPacketMaxSize);
containerConfig[config_key::initPacketJunkSize] = serverConfigMap.value(config_key::initPacketJunkSize);
containerConfig[config_key::responsePacketJunkSize] = serverConfigMap.value(config_key::responsePacketJunkSize);
containerConfig[config_key::initPacketMagicHeader] = serverConfigMap.value(config_key::initPacketMagicHeader);
containerConfig[config_key::responsePacketMagicHeader] = serverConfigMap.value(config_key::responsePacketMagicHeader);
containerConfig[config_key::underloadPacketMagicHeader] = serverConfigMap.value(config_key::underloadPacketMagicHeader);
containerConfig[config_key::transportPacketMagicHeader] = serverConfigMap.value(config_key::transportPacketMagicHeader);
}
config.insert(config_key::container, ContainerProps::containerToString(container));
}
config.insert(ProtocolProps::protoToString(protocol), containerConfig);

View File

@@ -333,7 +333,7 @@ namespace libssh {
switch (errorCode) {
case(SSH_NO_ERROR): return ErrorCode::NoError;
case(SSH_REQUEST_DENIED): return ErrorCode::SshRequestDeniedError;
case(SSH_REQUEST_DENIED): return ErrorCode::SshRequsetDeniedError;
case(SSH_EINTR): return ErrorCode::SshInterruptedError;
case(SSH_FATAL): return ErrorCode::SshInternalError;
default: return ErrorCode::SshInternalError;

View File

@@ -359,23 +359,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
if (!parseStringList(obj, "vpnDisabledApps", config.m_vpnDisabledApps)) {
return false;
}
if (!obj.value("Jc").isNull() && !obj.value("Jmin").isNull()
&& !obj.value("Jmax").isNull() && !obj.value("S1").isNull()
&& !obj.value("S2").isNull() && !obj.value("H1").isNull()
&& !obj.value("H2").isNull() && !obj.value("H3").isNull()
&& !obj.value("H4").isNull()) {
config.m_junkPacketCount = obj.value("Jc").toString();
config.m_junkPacketMinSize = obj.value("Jmin").toString();
config.m_junkPacketMaxSize = obj.value("Jmax").toString();
config.m_initPacketJunkSize = obj.value("S1").toString();
config.m_responsePacketJunkSize = obj.value("S2").toString();
config.m_initPacketMagicHeader = obj.value("H1").toString();
config.m_responsePacketMagicHeader = obj.value("H2").toString();
config.m_underloadPacketMagicHeader = obj.value("H3").toString();
config.m_transportPacketMagicHeader = obj.value("H4").toString();
}
return true;
}

View File

@@ -97,34 +97,6 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
out << "DNS = " << dnsServers.join(", ") << "\n";
}
if (!m_junkPacketCount.isNull()) {
out << "Jc = " << m_junkPacketCount << "\n";
}
if (!m_junkPacketMinSize.isNull()) {
out << "JMin = " << m_junkPacketMinSize << "\n";
}
if (!m_junkPacketMaxSize.isNull()) {
out << "JMax = " << m_junkPacketMaxSize << "\n";
}
if (!m_initPacketJunkSize.isNull()) {
out << "S1 = " << m_initPacketJunkSize << "\n";
}
if (!m_responsePacketJunkSize.isNull()) {
out << "S2 = " << m_responsePacketJunkSize << "\n";
}
if (!m_initPacketMagicHeader.isNull()) {
out << "H1 = " << m_initPacketMagicHeader << "\n";
}
if (!m_responsePacketMagicHeader.isNull()) {
out << "H2 = " << m_responsePacketMagicHeader << "\n";
}
if (!m_underloadPacketMagicHeader.isNull()) {
out << "H3 = " << m_underloadPacketMagicHeader << "\n";
}
if (!m_transportPacketMagicHeader.isNull()) {
out << "H4 = " << m_transportPacketMagicHeader << "\n";
}
// If any extra config was provided, append it now.
for (const QString& key : extra.keys()) {
out << key << " = " << extra[key] << "\n";

View File

@@ -40,16 +40,6 @@ class InterfaceConfig {
QString m_installationId;
#endif
QString m_junkPacketCount;
QString m_junkPacketMinSize;
QString m_junkPacketMaxSize;
QString m_initPacketJunkSize;
QString m_responsePacketJunkSize;
QString m_initPacketMagicHeader;
QString m_responsePacketMagicHeader;
QString m_underloadPacketMagicHeader;
QString m_transportPacketMagicHeader;
QJsonObject toJson() const;
QString toWgConf(
const QMap<QString, QString>& extra = QMap<QString, QString>()) const;

View File

@@ -1,6 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="x, &#195;&#151;, close">
<path id="Vector" d="M18 6L6 18" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M6 6L18 18" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 374 B

View File

@@ -1,6 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="search">
<path id="Vector" d="M11 19C15.4183 19 19 15.4183 19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11C3 15.4183 6.58172 19 11 19Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M21.0004 20.9984L16.6504 16.6484" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 483 B

View File

@@ -1,5 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15 9L9 15" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9 9L15 15" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 518 B

View File

@@ -58,7 +58,7 @@ target_link_libraries(networkextension PRIVATE ${FW_UI_KIT})
target_compile_options(networkextension PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\")
target_compile_options(networkextension PRIVATE -DNETWORK_EXTENSION=1)
set(WG_APPLE_SOURCE_DIR ${CLIENT_ROOT_DIR}/3rd/awg-apple/Sources)
set(WG_APPLE_SOURCE_DIR ${CLIENT_ROOT_DIR}/3rd/wireguard-apple/Sources)
target_sources(networkextension PRIVATE
${WG_APPLE_SOURCE_DIR}/WireGuardKit/WireGuardAdapter.swift

View File

@@ -1,6 +1,6 @@
#include "wireguard-go-version.h"
#include "3rd/awg-apple/Sources/WireGuardKitGo/wireguard.h"
#include "3rd/awg-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include "3rd/wireguard-apple/Sources/WireGuardKitGo/wireguard.h"
#include "3rd/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include <stdbool.h>
#include <stdint.h>

View File

@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "wireguard-go-version.h"
#include "3rd/awg-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include "3rd/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include <stdbool.h>
#include <stdint.h>

View File

@@ -4,7 +4,7 @@
#include "macos/gobridge/wireguard.h"
#include "wireguard-go-version.h"
#include "3rd/awg-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include "3rd/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include "3rd/ShadowSocks/ShadowSocks/ShadowSocks.h"
#include "platforms/ios/ssconnectivity.h"
#include "platforms/ios/iosopenvpn2ssadapter.h"

View File

@@ -26,11 +26,6 @@ int main(int argc, char *argv[])
AllowSetForegroundWindow(ASFW_ANY);
#endif
// QTBUG-95974 QTBUG-95764 QTBUG-102168
#ifdef Q_OS_ANDROID
qputenv("QT_ANDROID_DISABLE_ACCESSIBILITY", "1");
#endif
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
AmneziaApplication app(argc, argv);
#else
@@ -58,6 +53,7 @@ int main(int argc, char *argv[])
app.setOrganizationName(ORGANIZATION_NAME);
app.setApplicationDisplayName(APPLICATION_NAME);
app.loadTranslator();
app.loadFonts();
bool doExec = app.parseCommands();

View File

@@ -115,13 +115,7 @@ void LocalSocketController::daemonConnected() {
}
void LocalSocketController::activate(const QJsonObject &rawConfig) {
QString protocolName = rawConfig.value("protocol").toString();
int splitTunnelType = rawConfig.value("splitTunnelType").toInt();
QJsonArray splitTunnelSites = rawConfig.value("splitTunnelSites").toArray();
QJsonObject wgConfig = rawConfig.value(protocolName + "_config_data").toObject();
QJsonObject wgConfig = rawConfig.value("wireguard_config_data").toObject();
QJsonObject json;
json.insert("type", "activate");
@@ -141,79 +135,23 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
QJsonArray jsAllowedIPAddesses;
QJsonArray plainAllowedIP = wgConfig.value(amnezia::config_key::allowed_ips).toArray();
QJsonArray defaultAllowedIP = QJsonArray::fromStringList(QString("0.0.0.0/0, ::/0").split(","));
QJsonObject range_ipv4;
range_ipv4.insert("address", "0.0.0.0");
range_ipv4.insert("range", 0);
range_ipv4.insert("isIpv6", false);
jsAllowedIPAddesses.append(range_ipv4);
if (plainAllowedIP != defaultAllowedIP && !plainAllowedIP.isEmpty()) {
// Use AllowedIP list from WG config bacouse of higer priority
for (auto v : plainAllowedIP) {
QString ipRange = v.toString();
qDebug() << "ipRange " << ipRange;
if (ipRange.split('/').size() > 1){
QJsonObject range;
range.insert("address", ipRange.split('/')[0]);
range.insert("range", atoi(ipRange.split('/')[1].toLocal8Bit()));
range.insert("isIpv6", false);
jsAllowedIPAddesses.append(range);
} else {
QJsonObject range;
range.insert("address",ipRange);
range.insert("range", 32);
range.insert("isIpv6", false);
jsAllowedIPAddesses.append(range);
}
}
} else {
// Use APP split tunnel
if (splitTunnelType == 0 || splitTunnelType == 2) {
QJsonObject range_ipv4;
range_ipv4.insert("address", "0.0.0.0");
range_ipv4.insert("range", 0);
range_ipv4.insert("isIpv6", false);
jsAllowedIPAddesses.append(range_ipv4);
QJsonObject range_ipv6;
range_ipv6.insert("address", "::");
range_ipv6.insert("range", 0);
range_ipv6.insert("isIpv6", true);
jsAllowedIPAddesses.append(range_ipv6);
}
if (splitTunnelType == 1) {
for (auto v : splitTunnelSites) {
QString ipRange = v.toString();
qDebug() << "ipRange " << ipRange;
if (ipRange.split('/').size() > 1){
QJsonObject range;
range.insert("address", ipRange.split('/')[0]);
range.insert("range", atoi(ipRange.split('/')[1].toLocal8Bit()));
range.insert("isIpv6", false);
jsAllowedIPAddesses.append(range);
} else {
QJsonObject range;
range.insert("address",ipRange);
range.insert("range", 32);
range.insert("isIpv6", false);
jsAllowedIPAddesses.append(range);
}
}
}
}
QJsonObject range_ipv6;
range_ipv6.insert("address", "::");
range_ipv6.insert("range", 0);
range_ipv6.insert("isIpv6", true);
jsAllowedIPAddesses.append(range_ipv6);
json.insert("allowedIPAddressRanges", jsAllowedIPAddesses);
QJsonArray jsExcludedAddresses;
jsExcludedAddresses.append(wgConfig.value(amnezia::config_key::hostName));
if (splitTunnelType == 2) {
for (auto v : splitTunnelSites) {
QString ipRange = v.toString();
jsExcludedAddresses.append(ipRange);
}
}
json.insert("excludedAddresses", jsExcludedAddresses);
@@ -222,19 +160,6 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
// splitTunnelApps.append(QJsonValue(uri));
// }
// json.insert("vpnDisabledApps", splitTunnelApps);
if (protocolName == amnezia::config_key::awg) {
json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount));
json.insert(amnezia::config_key::junkPacketMinSize, wgConfig.value(amnezia::config_key::junkPacketMinSize));
json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize));
json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize));
json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize));
json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader));
json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader));
json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader));
json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader));
}
write(json);
}

View File

@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "3rd/awg-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include "3rd/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include <stdbool.h>
#include <stdint.h>

View File

@@ -28,8 +28,6 @@ struct MessageKey
static const char *host;
static const char *port;
static const char *isOnDemand;
static const char *SplitTunnelType;
static const char *SplitTunnelSites;
};
class IosController : public QObject
@@ -64,7 +62,6 @@ private:
bool setupOpenVPN();
bool setupCloak();
bool setupWireGuard();
bool setupAwg();
bool startOpenVPN(const QString &config);
bool startWireGuard(const QString &jsonConfig);

View File

@@ -29,9 +29,6 @@ const char* MessageKey::errorCode = "errorCode";
const char* MessageKey::host = "host";
const char* MessageKey::port = "port";
const char* MessageKey::isOnDemand = "is-on-demand";
const char* MessageKey::SplitTunnelType = "SplitTunnelType";
const char* MessageKey::SplitTunnelSites = "SplitTunnelSites";
Vpn::ConnectionState iosStatusToState(NEVPNStatus status) {
switch (status) {
@@ -207,9 +204,6 @@ bool IosController::connectVpn(amnezia::Proto proto, const QJsonObject& configur
if (proto == amnezia::Proto::WireGuard) {
return setupWireGuard();
}
if (proto == amnezia::Proto::Awg) {
return setupAwg();
}
return false;
}
@@ -313,15 +307,6 @@ bool IosController::setupWireGuard()
return startWireGuard(wgConfig);
}
bool IosController::setupAwg()
{
QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::Awg)].toObject();
QString wgConfig = config[config_key::config].toString();
return startWireGuard(wgConfig);
}
bool IosController::startOpenVPN(const QString &config)
{
qDebug() << "IosController::startOpenVPN";
@@ -354,13 +339,6 @@ void IosController::startTunnel()
{
m_rxBytes = 0;
m_txBytes = 0;
int STT = m_rawConfig["splitTunnelType"].toInt();
QJsonArray splitTunnelSites = m_rawConfig["splitTunnelSites"].toArray();
QJsonDocument doc;
doc.setArray(splitTunnelSites);
QString STS(doc.toJson());
[m_currentTunnel setEnabled:YES];
[m_currentTunnel saveToPreferencesWithCompletionHandler:^(NSError *saveError) {
@@ -386,15 +364,8 @@ void IosController::startTunnel()
NSString *actionValue = [NSString stringWithUTF8String:Action::start];
NSString *tunnelIdKey = [NSString stringWithUTF8String:MessageKey::tunnelId];
NSString *tunnelIdValue = !m_tunnelId.isEmpty() ? m_tunnelId.toNSString() : @"";
NSString *SplitTunnelTypeKey = [NSString stringWithUTF8String:MessageKey::SplitTunnelType];
NSString *SplitTunnelTypeValue = [NSString stringWithFormat:@"%d",STT];
NSString *SplitTunnelSitesKey = [NSString stringWithUTF8String:MessageKey::SplitTunnelSites];
NSString *SplitTunnelSitesValue = STS.toNSString();
NSDictionary* message = @{actionKey: actionValue, tunnelIdKey: tunnelIdValue,
SplitTunnelTypeKey: SplitTunnelTypeValue, SplitTunnelSitesKey: SplitTunnelSitesValue};
NSDictionary* message = @{actionKey: actionValue, tunnelIdKey: tunnelIdValue};
sendVpnExtensionMessage(message);

View File

@@ -15,7 +15,7 @@ struct Constants {
static let ovpnConfigKey = "ovpn"
static let wireGuardConfigKey = "wireguard"
static let loggerTag = "NET"
static let kActionStart = "start"
static let kActionRestart = "restart"
static let kActionStop = "stop"
@@ -29,8 +29,6 @@ struct Constants {
static let kMessageKeyHost = "host"
static let kMessageKeyPort = "port"
static let kMessageKeyOnDemand = "is-on-demand"
static let kMessageKeySplitTunnelType = "SplitTunnelType"
static let kMessageKeySplitTunnelSites = "SplitTunnelSites"
}
class PacketTunnelProvider: NEPacketTunnelProvider {
@@ -40,7 +38,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
wg_log(logLevel.osLogLevel, message: message)
}
}()
private lazy var ovpnAdapter: OpenVPNAdapter = {
let adapter = OpenVPNAdapter()
adapter.delegate = self
@@ -51,11 +49,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
private let dispatchQueue = DispatchQueue(label: "PacketTunnel", qos: .utility)
private var openVPNConfig: Data? = nil
private var SplitTunnelType: String? = nil
private var SplitTunnelSites: String? = nil
let vpnReachability = OpenVPNReachability()
var startHandler: ((Error?) -> Void)?
var stopHandler: (() -> Void)?
var protoType: TunnelProtoType = .none
@@ -67,34 +63,26 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
}
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
let tmpStr = String(data: messageData, encoding: .utf8)!
wg_log(.error, message: tmpStr)
guard let message = try? JSONSerialization.jsonObject(with: messageData, options: []) as? [String: Any] else {
Logger.global?.log(message: "Failed to serialize message from app")
return
}
guard let completionHandler = completionHandler else {
Logger.global?.log(message: "Missing message completion handler")
return
}
guard let action = message[Constants.kMessageKeyAction] as? String else {
Logger.global?.log(message: "Missing action key in app message")
completionHandler(nil)
return
}
if action == Constants.kActionStatus {
handleStatusAppMessage(messageData, completionHandler: completionHandler)
}
if action == Constants.kActionStart {
SplitTunnelType = message[Constants.kMessageKeySplitTunnelType] as? String
SplitTunnelSites = message[Constants.kMessageKeySplitTunnelSites] as? String
}
let callbackWrapper: (NSNumber?) -> Void = { errorCode in
//let tunnelId = self.tunnelConfig?.id ?? ""
let response: [String: Any] = [
@@ -102,11 +90,11 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
Constants.kMessageKeyErrorCode: errorCode ?? NSNull(),
Constants.kMessageKeyTunnelId: 0
]
completionHandler(try? JSONSerialization.data(withJSONObject: response, options: []))
}
}
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
dispatchQueue.async {
let activationAttemptId = options?[Constants.kActivationAttemptId] as? String
@@ -130,8 +118,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
switch self.protoType {
case .wireguard:
self.startWireguard(activationAttemptId: activationAttemptId,
errorNotifier: errorNotifier,
completionHandler: completionHandler)
errorNotifier: errorNotifier,
completionHandler: completionHandler)
case .openvpn:
self.startOpenVPN(completionHandler: completionHandler)
case .shadowsocks:
@@ -168,7 +156,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
handleOpenVPNStatusMessage(messageData, completionHandler: completionHandler)
case .shadowsocks:
break
// handleShadowSocksAppMessage(messageData, completionHandler: completionHandler)
// handleShadowSocksAppMessage(messageData, completionHandler: completionHandler)
case .none:
break
@@ -180,13 +168,12 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
errorNotifier: ErrorNotifier,
completionHandler: @escaping (Error?) -> Void) {
guard let protocolConfiguration = self.protocolConfiguration as? NETunnelProviderProtocol,
let providerConfiguration = protocolConfiguration.providerConfiguration,
let wgConfig: Data = providerConfiguration[Constants.wireGuardConfigKey] as? Data else {
wg_log(.error, message: "Can't start WireGuard config missing")
completionHandler(nil)
return
}
let providerConfiguration = protocolConfiguration.providerConfiguration,
let wgConfig: Data = providerConfiguration[Constants.wireGuardConfigKey] as? Data else {
wg_log(.error, message: "Can't start WireGuard config missing")
completionHandler(nil)
return
}
let wgConfigStr = String(data: wgConfig, encoding: .utf8)!
@@ -195,49 +182,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
completionHandler(nil)
return
}
if (tunnelConfiguration.peers.first!.allowedIPs.map { $0.stringRepresentation }.joined(separator: ", ") == "0.0.0.0/0, ::/0") {
if (SplitTunnelType == "1") {
for index in tunnelConfiguration.peers.indices {
tunnelConfiguration.peers[index].allowedIPs.removeAll()
var allowedIPs = [IPAddressRange]()
let STSdata = Data(SplitTunnelSites!.utf8)
do {
let STSArray = try JSONSerialization.jsonObject(with: STSdata) as! [String]
for allowedIPString in STSArray {
if let allowedIP = IPAddressRange(from: allowedIPString) {
allowedIPs.append(allowedIP)
}
}
} catch {
wg_log(.error,message: "Parse JSONSerialization Error")
}
tunnelConfiguration.peers[index].allowedIPs = allowedIPs
}
} else {
if (SplitTunnelType == "2")
{
for index in tunnelConfiguration.peers.indices {
var excludeIPs = [IPAddressRange]()
let STSdata = Data(SplitTunnelSites!.utf8)
do {
let STSarray = try JSONSerialization.jsonObject(with: STSdata) as! [String]
for excludeIPString in STSarray {
if let excludeIP = IPAddressRange(from: excludeIPString) {
excludeIPs.append(excludeIP)
}
}
} catch {
wg_log(.error,message: "Parse JSONSerialization Error")
}
tunnelConfiguration.peers[index].excludeIPs = excludeIPs
}
}
}
}
wg_log(.info, message: "Starting wireguard tunnel from the " + (activationAttemptId == nil ? "OS directly, rather than the app" : "app"))
// Start the tunnel
@@ -248,30 +193,30 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
completionHandler(nil)
return
}
switch adapterError {
case .cannotLocateTunnelFileDescriptor:
wg_log(.error, staticMessage: "Starting tunnel failed: could not determine file descriptor")
errorNotifier.notify(PacketTunnelProviderError.couldNotDetermineFileDescriptor)
completionHandler(PacketTunnelProviderError.couldNotDetermineFileDescriptor)
case .dnsResolution(let dnsErrors):
let hostnamesWithDnsResolutionFailure = dnsErrors.map { $0.address }
.joined(separator: ", ")
wg_log(.error, message: "DNS resolution failed for the following hostnames: \(hostnamesWithDnsResolutionFailure)")
errorNotifier.notify(PacketTunnelProviderError.dnsResolutionFailure)
completionHandler(PacketTunnelProviderError.dnsResolutionFailure)
case .setNetworkSettings(let error):
wg_log(.error, message: "Starting tunnel failed with setTunnelNetworkSettings returning \(error.localizedDescription)")
errorNotifier.notify(PacketTunnelProviderError.couldNotSetNetworkSettings)
completionHandler(PacketTunnelProviderError.couldNotSetNetworkSettings)
case .startWireGuardBackend(let errorCode):
wg_log(.error, message: "Starting tunnel failed with wgTurnOn returning \(errorCode)")
errorNotifier.notify(PacketTunnelProviderError.couldNotStartBackend)
completionHandler(PacketTunnelProviderError.couldNotStartBackend)
case .invalidState:
// Must never happen
fatalError()
@@ -281,27 +226,27 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
private func startOpenVPN(completionHandler: @escaping (Error?) -> Void) {
guard let protocolConfiguration = self.protocolConfiguration as? NETunnelProviderProtocol,
let providerConfiguration = protocolConfiguration.providerConfiguration,
let providerConfiguration = protocolConfiguration.providerConfiguration,
let ovpnConfiguration: Data = providerConfiguration[Constants.ovpnConfigKey] as? Data else {
// TODO: handle errors properly
wg_log(.error, message: "Can't start startOpenVPN()")
wg_log(.error, message: "Can't start startOpenVPN()")
return
}
setupAndlaunchOpenVPN(withConfig: ovpnConfiguration, completionHandler: completionHandler)
}
private func stopWireguard(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
wg_log(.info, staticMessage: "Stopping tunnel")
wgAdapter.stop { error in
ErrorNotifier.removeLastErrorFile()
if let error = error {
wg_log(.error, message: "Failed to stop WireGuard adapter: \(error.localizedDescription)")
}
completionHandler()
#if os(macOS)
// HACK: This is a filthy hack to work around Apple bug 32073323 (dup'd by us as 47526107).
// Remove it when they finally fix this upstream and the fix has been rolled out to
@@ -318,7 +263,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
}
ovpnAdapter.disconnect()
}
func handleWireguardStatusMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
guard let completionHandler = completionHandler else { return }
wgAdapter.getRuntimeConfiguration { settings in
@@ -333,8 +278,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
for component in components{
let pair = component.components(separatedBy: "=")
if pair.count == 2 {
settingsDictionary[pair[0]] = pair[1]
}
settingsDictionary[pair[0]] = pair[1]
}
}
let response: [String: Any] = [
@@ -364,7 +309,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
completionHandler(nil)
return
}
do {
let tunnelConfiguration = try TunnelConfiguration(fromWgQuickConfig: configString)
wgAdapter.update(tunnelConfiguration: tunnelConfiguration) { error in
@@ -373,7 +318,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
completionHandler(nil)
return
}
self.wgAdapter.getRuntimeConfiguration { settings in
var data: Data?
if let settings = settings {
@@ -389,76 +334,76 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
completionHandler(nil)
}
}
private func handleOpenVPNStatusMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
guard let completionHandler = completionHandler else { return }
let bytesin = ovpnAdapter.transportStatistics.bytesIn
let bytesout = ovpnAdapter.transportStatistics.bytesOut
let response: [String: Any] = [
"rx_bytes" : bytesin,
"tx_bytes" : bytesout
]
completionHandler(try? JSONSerialization.data(withJSONObject: response, options: []))
let bytesin = ovpnAdapter.transportStatistics.bytesIn
let bytesout = ovpnAdapter.transportStatistics.bytesOut
let response: [String: Any] = [
"rx_bytes" : bytesin,
"tx_bytes" : bytesout
]
completionHandler(try? JSONSerialization.data(withJSONObject: response, options: []))
}
// TODO review
private func setupAndlaunchOpenVPN(withConfig ovpnConfiguration: Data, withShadowSocks viaSS: Bool = false, completionHandler: @escaping (Error?) -> Void) {
wg_log(.info, message: "setupAndlaunchOpenVPN")
let str = String(decoding: ovpnConfiguration, as: UTF8.self)
let configuration = OpenVPNConfiguration()
configuration.fileContent = ovpnConfiguration
if(str.contains("cloak")){
configuration.setPTCloak();
}
let evaluation: OpenVPNConfigurationEvaluation
do {
evaluation = try ovpnAdapter.apply(configuration: configuration)
} catch {
completionHandler(error)
return
}
if !evaluation.autologin {
wg_log(.info, message: "Implement login with user credentials")
}
vpnReachability.startTracking { [weak self] status in
guard status == .reachableViaWiFi else { return }
self?.ovpnAdapter.reconnect(afterTimeInterval: 5)
}
startHandler = completionHandler
ovpnAdapter.connect(using: packetFlow)
// let ifaces = Interface.allInterfaces()
// .filter { $0.family == .ipv4 }
// .map { iface in iface.name }
// wg_log(.error, message: "Available TUN Interfaces: \(ifaces)")
// let ifaces = Interface.allInterfaces()
// .filter { $0.family == .ipv4 }
// .map { iface in iface.name }
// wg_log(.error, message: "Available TUN Interfaces: \(ifaces)")
}
// MARK: -- Network observing methods
private func startListeningForNetworkChanges() {
stopListeningForNetworkChanges()
addObserver(self, forKeyPath: Constants.kDefaultPathKey, options: .old, context: nil)
}
private func stopListeningForNetworkChanges() {
removeObserver(self, forKeyPath: Constants.kDefaultPathKey)
}
override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
guard Constants.kDefaultPathKey != keyPath else { return }
// Since iOS 11, we have observed that this KVO event fires repeatedly when connecting over Wifi,
// even though the underlying network has not changed (i.e. `isEqualToPath` returns false),
@@ -467,28 +412,28 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
guard let lastPath: NWPath = change?[.oldKey] as? NWPath,
let defPath = defaultPath,
lastPath != defPath || lastPath.description != defPath.description else {
return
}
return
}
DispatchQueue.main.async { [weak self] in
guard let `self` = self, self.defaultPath != nil else { return }
self.handle(networkChange: self.defaultPath!) { _ in }
}
}
private func handle(networkChange changePath: NWPath, completion: @escaping (Error?) -> Void) {
wg_log(.info, message: "Tunnel restarted.")
startTunnel(options: nil, completionHandler: completion)
}
private func startEmptyTunnel(completionHandler: @escaping (Error?) -> Void) {
dispatchPrecondition(condition: .onQueue(dispatchQueue))
let emptyTunnelConfiguration = TunnelConfiguration(
name: nil,
interface: InterfaceConfiguration(privateKey: PrivateKey()),
peers: []
)
wgAdapter.start(tunnelConfiguration: emptyTunnelConfiguration) { error in
self.dispatchQueue.async {
if let error {
@@ -500,9 +445,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
}
}
}
let settings = NETunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1")
self.setTunnelNetworkSettings(settings) { error in
completionHandler(error)
}
@@ -533,50 +478,6 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate {
// send empty string to NEDNSSettings.matchDomains
networkSettings?.dnsSettings?.matchDomains = [""]
if (SplitTunnelType == "1") {
var ipv4IncludedRoutes = [NEIPv4Route]()
let STSdata = Data(SplitTunnelSites!.utf8)
do {
let STSarray = try JSONSerialization.jsonObject(with: STSdata) as! [String]
for allowedIPString in STSarray {
if let allowedIP = IPAddressRange(from: allowedIPString){
ipv4IncludedRoutes.append(NEIPv4Route(destinationAddress: "\(allowedIP.address)", subnetMask: "\(allowedIP.subnetMask())"))
}
}
} catch {
wg_log(.error,message: "Parse JSONSerialization Error")
}
networkSettings?.ipv4Settings?.includedRoutes = ipv4IncludedRoutes
} else {
if (SplitTunnelType == "2")
{
var ipv4ExcludedRoutes = [NEIPv4Route]()
var ipv4IncludedRoutes = [NEIPv4Route]()
var ipv6IncludedRoutes = [NEIPv6Route]()
let STSdata = Data(SplitTunnelSites!.utf8)
do {
let STSarray = try JSONSerialization.jsonObject(with: STSdata) as! [String]
for excludeIPString in STSarray {
if let excludeIP = IPAddressRange(from: excludeIPString) {
ipv4ExcludedRoutes.append(NEIPv4Route(destinationAddress: "\(excludeIP.address)", subnetMask: "\(excludeIP.subnetMask())"))
}
}
} catch {
wg_log(.error,message: "Parse JSONSerialization Error")
}
if let allIPv4 = IPAddressRange(from: "0.0.0.0/0"){
ipv4IncludedRoutes.append(NEIPv4Route(destinationAddress: "\(allIPv4.address)", subnetMask: "\(allIPv4.subnetMask())"))
}
if let allIPv6 = IPAddressRange(from: "::/0") {
ipv6IncludedRoutes.append(NEIPv6Route(destinationAddress: "\(allIPv6.address)", networkPrefixLength: NSNumber(value: allIPv6.networkPrefixLength)))
}
networkSettings?.ipv4Settings?.includedRoutes = ipv4IncludedRoutes
networkSettings?.ipv6Settings?.includedRoutes = ipv6IncludedRoutes
networkSettings?.ipv4Settings?.excludedRoutes = ipv4ExcludedRoutes
}
}
// Set the network settings for the current tunneling session.
setTunnelNetworkSettings(networkSettings, completionHandler: completionHandler)
}
@@ -637,7 +538,7 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate {
wg_log(.info, message: logMessage)
}
}
extension WireGuardLogLevel {
var osLogLevel: OSLogType {
switch self {

View File

@@ -158,15 +158,15 @@ bool LinuxRouteMonitor::rtmSendRoute(int action, int flags, int type,
return false;
}
nlmsg_append_attr32(nlmsg, sizeof(buf), RTA_OIF, index);
nlmsg_append_attr32(nlmsg, sizeof(buf), RTA_PRIORITY, 1);
}
if (rtm->rtm_type == RTN_THROW) {
struct in_addr ip4;
inet_pton(AF_INET, getgatewayandiface().toUtf8(), &ip4);
nlmsg_append_attr(nlmsg, sizeof(buf), RTA_GATEWAY, &ip4, sizeof(ip4));
nlmsg_append_attr32(nlmsg, sizeof(buf), RTA_PRIORITY, 0);
rtm->rtm_type = RTN_UNICAST;
int index = if_nametoindex(getgatewayandiface().toUtf8());
if (index <= 0) {
logger.error() << "if_nametoindex() failed:" << strerror(errno);
return false;
}
nlmsg_append_attr32(nlmsg, sizeof(buf), RTA_OIF, index);
}
struct sockaddr_nl nladdr;
@@ -334,7 +334,7 @@ QString LinuxRouteMonitor::getgatewayandiface()
}
}
close(sock);
return gateway_address;
return interface;
}
static bool buildAllowedIp(wg_allowedip* ip,

View File

@@ -100,19 +100,6 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) {
QTextStream out(&message);
out << "private_key=" << QString(privateKey.toHex()) << "\n";
out << "replace_peers=true\n";
if (config.m_junkPacketCount != "") {
out << "jc=" << config.m_junkPacketCount << "\n";
out << "jmin=" << config.m_junkPacketMinSize << "\n";
out << "jmax=" << config.m_junkPacketMaxSize << "\n";
out << "s1=" << config.m_initPacketJunkSize << "\n";
out << "s2=" << config.m_responsePacketJunkSize << "\n";
out << "h1=" << config.m_initPacketMagicHeader << "\n";
out << "h2=" << config.m_responsePacketMagicHeader << "\n";
out << "h3=" << config.m_underloadPacketMagicHeader << "\n";
out << "h4=" << config.m_transportPacketMagicHeader << "\n";
}
int err = uapiErrno(uapiCommand(message));
if (err != 0) {
logger.error() << "Interface configuration failed:" << strerror(err);

View File

@@ -100,19 +100,6 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) {
QTextStream out(&message);
out << "private_key=" << QString(privateKey.toHex()) << "\n";
out << "replace_peers=true\n";
if (config.m_junkPacketCount != "") {
out << "jc=" << config.m_junkPacketCount << "\n";
out << "jmin=" << config.m_junkPacketMinSize << "\n";
out << "jmax=" << config.m_junkPacketMaxSize << "\n";
out << "s1=" << config.m_initPacketJunkSize << "\n";
out << "s2=" << config.m_responsePacketJunkSize << "\n";
out << "h1=" << config.m_initPacketMagicHeader << "\n";
out << "h2=" << config.m_responsePacketMagicHeader << "\n";
out << "h3=" << config.m_underloadPacketMagicHeader << "\n";
out << "h4=" << config.m_transportPacketMagicHeader << "\n";
}
int err = uapiErrno(uapiCommand(message));
if (err != 0) {
logger.error() << "Interface configuration failed:" << strerror(err);

View File

@@ -236,17 +236,6 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
}
}
if (!config.m_excludedAddresses.empty()) {
for (const QString& i : config.m_excludedAddresses) {
logger.debug() << "range: " << i;
if (!allowTrafficToRange(i, HIGH_WEIGHT,
"Allow Ecxlude route", config.m_serverPublicKey)) {
return false;
}
}
}
result = FwpmTransactionCommit0(m_sessionHandle);
if (result != ERROR_SUCCESS) {
logger.error() << "FwpmTransactionCommit0 failed with error:" << result;
@@ -422,8 +411,8 @@ bool WindowsFirewall::allowTrafficOfAdapter(int networkAdapter, uint8_t weight,
}
bool WindowsFirewall::allowTrafficTo(const QHostAddress& targetIP, uint port,
int weight, const QString& title,
const QString& peer) {
int weight, const QString& title,
const QString& peer) {
bool isIPv4 = targetIP.protocol() == QAbstractSocket::IPv4Protocol;
GUID layerOut =
isIPv4 ? FWPM_LAYER_ALE_AUTH_CONNECT_V4 : FWPM_LAYER_ALE_AUTH_CONNECT_V6;
@@ -484,57 +473,6 @@ bool WindowsFirewall::allowTrafficTo(const QHostAddress& targetIP, uint port,
return true;
}
bool WindowsFirewall::allowTrafficToRange(const IPAddress& addr, uint8_t weight,
const QString& title,
const QString& peer) {
QString description("Allow traffic %1 %2 ");
auto lower = addr.address();
auto upper = addr.broadcastAddress();
const bool isV4 = addr.type() == QAbstractSocket::IPv4Protocol;
const GUID layerKeyOut =
isV4 ? FWPM_LAYER_ALE_AUTH_CONNECT_V4 : FWPM_LAYER_ALE_AUTH_CONNECT_V6;
const GUID layerKeyIn = isV4 ? FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4
: FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6;
// Assemble the Filter base
FWPM_FILTER0 filter;
memset(&filter, 0, sizeof(filter));
filter.action.type = FWP_ACTION_PERMIT;
filter.weight.type = FWP_UINT8;
filter.weight.uint8 = weight;
filter.subLayerKey = ST_FW_WINFW_BASELINE_SUBLAYER_KEY;
FWPM_FILTER_CONDITION0 cond[1] = {0};
FWP_RANGE0 ipRange;
QByteArray lowIpV6Buffer;
QByteArray highIpV6Buffer;
importAddress(lower, ipRange.valueLow, &lowIpV6Buffer);
importAddress(upper, ipRange.valueHigh, &highIpV6Buffer);
cond[0].fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS;
cond[0].matchType = FWP_MATCH_RANGE;
cond[0].conditionValue.type = FWP_RANGE_TYPE;
cond[0].conditionValue.rangeValue = &ipRange;
filter.numFilterConditions = 1;
filter.filterCondition = cond;
filter.layerKey = layerKeyOut;
if (!enableFilter(&filter, title, description.arg("to").arg(addr.toString()),
peer)) {
return false;
}
filter.layerKey = layerKeyIn;
if (!enableFilter(&filter, title,
description.arg("from").arg(addr.toString()), peer)) {
return false;
}
return true;
}
bool WindowsFirewall::allowDHCPTraffic(uint8_t weight, const QString& title) {
// Allow outbound DHCPv4
{

View File

@@ -52,9 +52,6 @@ class WindowsFirewall final : public QObject {
bool blockTrafficOnPort(uint port, uint8_t weight, const QString& title);
bool allowTrafficTo(const QHostAddress& targetIP, uint port, int weight,
const QString& title, const QString& peer = QString());
bool allowTrafficToRange(const IPAddress& addr, uint8_t weight,
const QString& title,
const QString& peer);
bool allowTrafficOfAdapter(int networkAdapter, uint8_t weight,
const QString& title);
bool allowDHCPTraffic(uint8_t weight, const QString& title);

View File

@@ -1,10 +0,0 @@
#include "awgprotocol.h"
Awg::Awg(const QJsonObject &configuration, QObject *parent)
: WireguardProtocol(configuration, parent)
{
}
Awg::~Awg()
{
}

View File

@@ -1,17 +0,0 @@
#ifndef AWGPROTOCOL_H
#define AWGPROTOCOL_H
#include <QObject>
#include "wireguardprotocol.h"
class Awg : public WireguardProtocol
{
Q_OBJECT
public:
explicit Awg(const QJsonObject &configuration, QObject *parent = nullptr);
virtual ~Awg() override;
};
#endif // AWGPROTOCOL_H

View File

@@ -1,7 +1,5 @@
#include "protocols_defs.h"
#include <QRandomGenerator>
using namespace amnezia;
QDebug operator<<(QDebug debug, const amnezia::ProtocolEnumNS::Proto &p)
@@ -68,12 +66,12 @@ QMap<amnezia::Proto, QString> ProtocolProps::protocolHumanNames()
{ Proto::ShadowSocks, "ShadowSocks" },
{ Proto::Cloak, "Cloak" },
{ Proto::WireGuard, "WireGuard" },
{ Proto::Awg, "AmneziaWG" },
{ Proto::Ikev2, "IKEv2" },
{ Proto::L2tp, "L2TP" },
{ Proto::TorWebSite, "Website in Tor network" },
{ Proto::Dns, "DNS Service" },
{ Proto::FileShare, "File Sharing Service" },
{ Proto::Sftp, QObject::tr("Sftp service") } };
}
@@ -90,43 +88,27 @@ amnezia::ServiceType ProtocolProps::protocolService(Proto p)
case Proto::Cloak: return ServiceType::Vpn;
case Proto::ShadowSocks: return ServiceType::Vpn;
case Proto::WireGuard: return ServiceType::Vpn;
case Proto::Awg: return ServiceType::Vpn;
case Proto::Ikev2: return ServiceType::Vpn;
case Proto::TorWebSite: return ServiceType::Other;
case Proto::Dns: return ServiceType::Other;
case Proto::Sftp: return ServiceType::Other;
case Proto::FileShare: return ServiceType::Other;
default: return ServiceType::Other;
}
}
int ProtocolProps::getPortForInstall(Proto p)
{
switch (p) {
case Awg:
case WireGuard:
case ShadowSocks:
case OpenVpn:
return QRandomGenerator::global()->bounded(30000, 50000);
default:
return defaultPort(p);
}
}
int ProtocolProps::defaultPort(Proto p)
{
switch (p) {
case Proto::Any: return -1;
case Proto::OpenVpn: return QString(protocols::openvpn::defaultPort).toInt();
case Proto::Cloak: return QString(protocols::cloak::defaultPort).toInt();
case Proto::ShadowSocks: return QString(protocols::shadowsocks::defaultPort).toInt();
case Proto::WireGuard: return QString(protocols::wireguard::defaultPort).toInt();
case Proto::Awg: return QString(protocols::awg::defaultPort).toInt();
case Proto::OpenVpn: return 1194;
case Proto::Cloak: return 443;
case Proto::ShadowSocks: return 6789;
case Proto::WireGuard: return 51820;
case Proto::Ikev2: return -1;
case Proto::L2tp: return -1;
case Proto::TorWebSite: return -1;
case Proto::Dns: return 53;
case Proto::FileShare: return 139;
case Proto::Sftp: return 222;
default: return -1;
}
@@ -140,14 +122,13 @@ bool ProtocolProps::defaultPortChangeable(Proto p)
case Proto::Cloak: return true;
case Proto::ShadowSocks: return true;
case Proto::WireGuard: return true;
case Proto::Awg: return true;
case Proto::Ikev2: return false;
case Proto::L2tp: return false;
case Proto::TorWebSite: return false;
case Proto::TorWebSite: return true;
case Proto::Dns: return false;
case Proto::Sftp: return true;
default: return false;
case Proto::FileShare: return false;
default: return -1;
}
}
@@ -159,12 +140,12 @@ TransportProto ProtocolProps::defaultTransportProto(Proto p)
case Proto::Cloak: return TransportProto::Tcp;
case Proto::ShadowSocks: return TransportProto::Tcp;
case Proto::WireGuard: return TransportProto::Udp;
case Proto::Awg: return TransportProto::Udp;
case Proto::Ikev2: return TransportProto::Udp;
case Proto::L2tp: return TransportProto::Udp;
// non-vpn
case Proto::TorWebSite: return TransportProto::Tcp;
case Proto::Dns: return TransportProto::Udp;
case Proto::FileShare: return TransportProto::Udp;
case Proto::Sftp: return TransportProto::Tcp;
}
}
@@ -177,12 +158,12 @@ bool ProtocolProps::defaultTransportProtoChangeable(Proto p)
case Proto::Cloak: return false;
case Proto::ShadowSocks: return false;
case Proto::WireGuard: return false;
case Proto::Awg: return false;
case Proto::Ikev2: return false;
case Proto::L2tp: return false;
// non-vpn
case Proto::TorWebSite: return false;
case Proto::Dns: return false;
case Proto::FileShare: return false;
case Proto::Sftp: return false;
default: return false;
}

View File

@@ -2,8 +2,8 @@
#define PROTOCOLS_DEFS_H
#include <QDebug>
#include <QMetaEnum>
#include <QObject>
#include <QMetaEnum>
namespace amnezia
{
@@ -43,7 +43,6 @@ namespace amnezia
constexpr char server_priv_key[] = "server_priv_key";
constexpr char server_pub_key[] = "server_pub_key";
constexpr char psk_key[] = "psk_key";
constexpr char allowed_ips[] = "allowed_ips";
constexpr char client_ip[] = "client_ip"; // internal ip address
@@ -62,25 +61,11 @@ namespace amnezia
constexpr char isThirdPartyConfig[] = "isThirdPartyConfig";
constexpr char junkPacketCount[] = "Jc";
constexpr char junkPacketMinSize[] = "Jmin";
constexpr char junkPacketMaxSize[] = "Jmax";
constexpr char initPacketJunkSize[] = "S1";
constexpr char responsePacketJunkSize[] = "S2";
constexpr char initPacketMagicHeader[] = "H1";
constexpr char responsePacketMagicHeader[] = "H2";
constexpr char underloadPacketMagicHeader[] = "H3";
constexpr char transportPacketMagicHeader[] = "H4";
constexpr char openvpn[] = "openvpn";
constexpr char wireguard[] = "wireguard";
constexpr char shadowsocks[] = "shadowsocks";
constexpr char cloak[] = "cloak";
constexpr char sftp[] = "sftp";
constexpr char awg[] = "awg";
constexpr char splitTunnelSites[] = "splitTunnelSites";
constexpr char splitTunnelType[] = "splitTunnelType";
}
@@ -155,25 +140,6 @@ namespace amnezia
} // namespace sftp
namespace awg
{
constexpr char defaultPort[] = "55424";
constexpr char serverConfigPath[] = "/opt/amnezia/awg/wg0.conf";
constexpr char serverPublicKeyPath[] = "/opt/amnezia/awg/wireguard_server_public_key.key";
constexpr char serverPskKeyPath[] = "/opt/amnezia/awg/wireguard_psk.key";
constexpr char defaultJunkPacketCount[] = "3";
constexpr char defaultJunkPacketMinSize[] = "10";
constexpr char defaultJunkPacketMaxSize[] = "30";
constexpr char defaultInitPacketJunkSize[] = "15";
constexpr char defaultResponsePacketJunkSize[] = "18";
constexpr char defaultInitPacketMagicHeader[] = "1020325451";
constexpr char defaultResponsePacketMagicHeader[] = "3288052141";
constexpr char defaultTransportPacketMagicHeader[] = "2528465083";
constexpr char defaultUnderloadPacketMagicHeader[] = "1766607858";
}
} // namespace protocols
namespace ProtocolEnumNS
@@ -192,13 +158,13 @@ namespace amnezia
ShadowSocks,
Cloak,
WireGuard,
Awg,
Ikev2,
L2tp,
// non-vpn
TorWebSite,
Dns,
FileShare,
Sftp
};
Q_ENUM_NS(Proto)
@@ -232,8 +198,6 @@ namespace amnezia
Q_INVOKABLE static ServiceType protocolService(Proto p);
Q_INVOKABLE static int getPortForInstall(Proto p);
Q_INVOKABLE static int defaultPort(Proto p);
Q_INVOKABLE static bool defaultPortChangeable(Proto p);

View File

@@ -1,21 +1,22 @@
#include <QDebug>
#include <QTimer>
#include "core/errorstrings.h"
#include "vpnprotocol.h"
#include "core/errorstrings.h"
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
#include "openvpnovercloakprotocol.h"
#include "openvpnprotocol.h"
#include "shadowsocksvpnprotocol.h"
#include "wireguardprotocol.h"
#include "openvpnprotocol.h"
#include "shadowsocksvpnprotocol.h"
#include "openvpnovercloakprotocol.h"
#include "wireguardprotocol.h"
#endif
#ifdef Q_OS_WINDOWS
#include "ikev2_vpn_protocol_windows.h"
#include "ikev2_vpn_protocol_windows.h"
#endif
VpnProtocol::VpnProtocol(const QJsonObject &configuration, QObject *parent)
VpnProtocol::VpnProtocol(const QJsonObject &configuration, QObject* parent)
: QObject(parent),
m_connectionState(Vpn::ConnectionState::Unknown),
m_rawConfig(configuration),
@@ -30,7 +31,7 @@ VpnProtocol::VpnProtocol(const QJsonObject &configuration, QObject *parent)
void VpnProtocol::setLastError(ErrorCode lastError)
{
m_lastError = lastError;
if (lastError) {
if (lastError){
setConnectionState(Vpn::ConnectionState::Error);
}
qCritical().noquote() << "VpnProtocol error, code" << m_lastError << errorString(m_lastError);
@@ -102,7 +103,7 @@ QString VpnProtocol::vpnGateway() const
return m_vpnGateway;
}
VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &configuration)
VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject& configuration)
{
switch (container) {
#if defined(Q_OS_WINDOWS)
@@ -113,7 +114,6 @@ VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &
case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration);
case DockerContainer::ShadowSocks: return new ShadowSocksVpnProtocol(configuration);
case DockerContainer::WireGuard: return new WireguardProtocol(configuration);
case DockerContainer::Awg: return new WireguardProtocol(configuration);
#endif
default: return nullptr;
}
@@ -135,7 +135,8 @@ QString VpnProtocol::textConnectionState(Vpn::ConnectionState connectionState)
case Vpn::ConnectionState::Disconnecting: return tr("Disconnecting...");
case Vpn::ConnectionState::Reconnecting: return tr("Reconnecting...");
case Vpn::ConnectionState::Error: return tr("Error");
default:;
default:
;
}
return QString();

View File

@@ -16,6 +16,8 @@ WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject *
m_configFile.setFileName(QDir::tempPath() + QDir::separator() + serviceName() + ".conf");
writeWireguardConfiguration(configuration);
// MZ
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_LINUX)
m_impl.reset(new LocalSocketController());
connect(m_impl.get(), &ControllerImpl::connected, this,
[this](const QString &pubkey, const QDateTime &connectionTimestamp) {
@@ -24,6 +26,7 @@ WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject *
connect(m_impl.get(), &ControllerImpl::disconnected, this,
[this]() { emit connectionStateChanged(Vpn::ConnectionState::Disconnected); });
m_impl->initialize(nullptr, nullptr);
#endif
}
WireguardProtocol::~WireguardProtocol()
@@ -34,12 +37,72 @@ WireguardProtocol::~WireguardProtocol()
void WireguardProtocol::stop()
{
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_LINUX)
stopMzImpl();
return;
#endif
if (!QFileInfo::exists(Utils::wireguardExecPath())) {
qCritical() << "Wireguard executable missing!";
setLastError(ErrorCode::ExecutableMissing);
return;
}
m_wireguardStopProcess = IpcClient::CreatePrivilegedProcess();
if (!m_wireguardStopProcess) {
qCritical() << "IpcProcess replica is not created!";
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
return;
}
m_wireguardStopProcess->waitForSource(1000);
if (!m_wireguardStopProcess->isInitialized()) {
qWarning() << "IpcProcess replica is not connected!";
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
return;
}
m_wireguardStopProcess->setProgram(PermittedProcess::Wireguard);
m_wireguardStopProcess->setArguments(stopArgs());
qDebug() << stopArgs().join(" ");
connect(m_wireguardStopProcess.data(), &PrivilegedProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
qDebug() << "WireguardProtocol::WireguardProtocol Stop errorOccurred" << error;
setConnectionState(Vpn::ConnectionState::Disconnected);
});
connect(m_wireguardStopProcess.data(), &PrivilegedProcess::stateChanged, this,
[this](QProcess::ProcessState newState) {
qDebug() << "WireguardProtocol::WireguardProtocol Stop stateChanged" << newState;
});
#ifdef Q_OS_LINUX
if (IpcClient::Interface()) {
QRemoteObjectPendingReply<bool> result = IpcClient::Interface()->isWireguardRunning();
if (result.returnValue()) {
setConnectionState(Vpn::ConnectionState::Disconnected);
return;
}
} else {
qCritical() << "IPC client not initialized";
setConnectionState(Vpn::ConnectionState::Disconnected);
return;
}
#endif
m_wireguardStopProcess->start();
m_wireguardStopProcess->waitForFinished(10000);
setConnectionState(Vpn::ConnectionState::Disconnected);
}
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_LINUX)
ErrorCode WireguardProtocol::startMzImpl()
{
qDebug() << "WireguardProtocol::startMzImpl():" << m_rawConfig;
m_impl->activate(m_rawConfig);
return ErrorCode::NoError;
}
@@ -49,6 +112,7 @@ ErrorCode WireguardProtocol::stopMzImpl()
m_impl->deactivate();
return ErrorCode::NoError;
}
#endif
void WireguardProtocol::writeWireguardConfiguration(const QJsonObject &configuration)
{
@@ -62,8 +126,21 @@ void WireguardProtocol::writeWireguardConfiguration(const QJsonObject &configura
m_configFile.write(jConfig.value(config_key::config).toString().toUtf8());
m_configFile.close();
#if 0
if (IpcClient::Interface()) {
QRemoteObjectPendingReply<bool> result = IpcClient::Interface()->copyWireguardConfig(m_configFile.fileName());
if (result.returnValue()) {
qCritical() << "Failed to copy wireguard config";
return;
}
} else {
qCritical() << "IPC client not initialized";
return;
}
m_configFileName = "/etc/wireguard/wg99.conf";
#else
m_configFileName = m_configFile.fileName();
#endif
m_isConfigLoaded = true;
@@ -77,9 +154,15 @@ QString WireguardProtocol::configPath() const
return m_configFileName;
}
QString WireguardProtocol::serviceName() const
void WireguardProtocol::updateRouteGateway(QString line)
{
return "AmneziaVPN.WireGuard0";
// TODO: fix for macos
line = line.split("ROUTE_GATEWAY", Qt::SkipEmptyParts).at(1);
if (!line.contains("/"))
return;
m_routeGateway = line.split("/", Qt::SkipEmptyParts).first();
m_routeGateway.replace(" ", "");
qDebug() << "Set VPN route gateway" << m_routeGateway;
}
ErrorCode WireguardProtocol::start()
@@ -89,6 +172,112 @@ ErrorCode WireguardProtocol::start()
return lastError();
}
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_LINUX)
return startMzImpl();
#endif
if (!QFileInfo::exists(Utils::wireguardExecPath())) {
setLastError(ErrorCode::ExecutableMissing);
return lastError();
}
if (IpcClient::Interface()) {
QRemoteObjectPendingReply<bool> result = IpcClient::Interface()->isWireguardConfigExists(configPath());
if (result.returnValue()) {
setLastError(ErrorCode::ConfigMissing);
return lastError();
}
} else {
qCritical() << "IPC client not initialized";
setLastError(ErrorCode::InternalError);
return lastError();
}
setConnectionState(Vpn::ConnectionState::Connecting);
m_wireguardStartProcess = IpcClient::CreatePrivilegedProcess();
if (!m_wireguardStartProcess) {
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
return ErrorCode::AmneziaServiceConnectionFailed;
}
m_wireguardStartProcess->waitForSource(1000);
if (!m_wireguardStartProcess->isInitialized()) {
qWarning() << "IpcProcess replica is not connected!";
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
return ErrorCode::AmneziaServiceConnectionFailed;
}
m_wireguardStartProcess->setProgram(PermittedProcess::Wireguard);
m_wireguardStartProcess->setArguments(startArgs());
qDebug() << startArgs().join(" ");
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
qDebug() << "WireguardProtocol::WireguardProtocol errorOccurred" << error;
setConnectionState(Vpn::ConnectionState::Disconnected);
});
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::stateChanged, this,
[this](QProcess::ProcessState newState) {
qDebug() << "WireguardProtocol::WireguardProtocol stateChanged" << newState;
});
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::finished, this,
[this]() { setConnectionState(Vpn::ConnectionState::Connected); });
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::readyRead, this, [this]() {
QRemoteObjectPendingReply<QByteArray> reply = m_wireguardStartProcess->readAll();
reply.waitForFinished(1000);
qDebug() << "WireguardProtocol::WireguardProtocol readyRead" << reply.returnValue();
});
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::readyReadStandardOutput, this, [this]() {
QRemoteObjectPendingReply<QByteArray> reply = m_wireguardStartProcess->readAllStandardOutput();
reply.waitForFinished(1000);
qDebug() << "WireguardProtocol::WireguardProtocol readAllStandardOutput" << reply.returnValue();
});
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::readyReadStandardError, this, [this]() {
QRemoteObjectPendingReply<QByteArray> reply = m_wireguardStartProcess->readAllStandardError();
reply.waitForFinished(10);
qDebug() << "WireguardProtocol::WireguardProtocol readAllStandardError" << reply.returnValue();
});
m_wireguardStartProcess->start();
m_wireguardStartProcess->waitForFinished(10000);
return ErrorCode::NoError;
}
void WireguardProtocol::updateVpnGateway(const QString &line)
{
}
QString WireguardProtocol::serviceName() const
{
return "AmneziaVPN.WireGuard0";
}
QStringList WireguardProtocol::stopArgs()
{
#ifdef Q_OS_WIN
return { "--remove", configPath() };
#elif defined Q_OS_LINUX
return { "down", "wg99" };
#else
return {};
#endif
}
QStringList WireguardProtocol::startArgs()
{
#ifdef Q_OS_WIN
return { "--add", configPath() };
#elif defined Q_OS_LINUX
return { "up", "wg99" };
#else
return {};
#endif
}

View File

@@ -8,6 +8,7 @@
#include <QTimer>
#include "vpnprotocol.h"
#include "core/ipcclient.h"
#include "mozilla/controllerimpl.h"
@@ -22,21 +23,33 @@ public:
ErrorCode start() override;
void stop() override;
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_LINUX)
ErrorCode startMzImpl();
ErrorCode stopMzImpl();
#endif
private:
QString configPath() const;
void writeWireguardConfiguration(const QJsonObject &configuration);
void updateRouteGateway(QString line);
void updateVpnGateway(const QString &line);
QString serviceName() const;
QStringList stopArgs();
QStringList startArgs();
private:
QString m_configFileName;
QFile m_configFile;
QSharedPointer<PrivilegedProcess> m_wireguardStartProcess;
QSharedPointer<PrivilegedProcess> m_wireguardStopProcess;
bool m_isConfigLoaded = false;
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_LINUX)
QScopedPointer<ControllerImpl> m_impl;
#endif
};
#endif // WIREGUARDPROTOCOL_H

View File

@@ -215,15 +215,5 @@
<file>ui/qml/Controls2/ListViewWithLabelsType.qml</file>
<file>ui/qml/Pages2/PageServiceDnsSettings.qml</file>
<file>ui/qml/Controls2/TopCloseButtonType.qml</file>
<file>images/controls/x-circle.svg</file>
<file>ui/qml/Pages2/PageProtocolAwgSettings.qml</file>
<file>server_scripts/awg/template.conf</file>
<file>server_scripts/awg/start.sh</file>
<file>server_scripts/awg/configure_container.sh</file>
<file>server_scripts/awg/run_container.sh</file>
<file>server_scripts/awg/Dockerfile</file>
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
<file>images/controls/close.svg</file>
<file>images/controls/search.svg</file>
</qresource>
</RCC>

View File

@@ -1,46 +0,0 @@
FROM amneziavpn/amnezia-wg:latest
LABEL maintainer="AmneziaVPN"
#Install required packages
RUN apk add --no-cache bash curl dumb-init
RUN apk --update upgrade --no-cache
RUN mkdir -p /opt/amnezia
RUN echo -e "#!/bin/bash\ntail -f /dev/null" > /opt/amnezia/start.sh
RUN chmod a+x /opt/amnezia/start.sh
# Tune network
RUN echo -e " \n\
fs.file-max = 51200 \n\
\n\
net.core.rmem_max = 67108864 \n\
net.core.wmem_max = 67108864 \n\
net.core.netdev_max_backlog = 250000 \n\
net.core.somaxconn = 4096 \n\
\n\
net.ipv4.tcp_syncookies = 1 \n\
net.ipv4.tcp_tw_reuse = 1 \n\
net.ipv4.tcp_tw_recycle = 0 \n\
net.ipv4.tcp_fin_timeout = 30 \n\
net.ipv4.tcp_keepalive_time = 1200 \n\
net.ipv4.ip_local_port_range = 10000 65000 \n\
net.ipv4.tcp_max_syn_backlog = 8192 \n\
net.ipv4.tcp_max_tw_buckets = 5000 \n\
net.ipv4.tcp_fastopen = 3 \n\
net.ipv4.tcp_mem = 25600 51200 102400 \n\
net.ipv4.tcp_rmem = 4096 87380 67108864 \n\
net.ipv4.tcp_wmem = 4096 65536 67108864 \n\
net.ipv4.tcp_mtu_probing = 1 \n\
net.ipv4.tcp_congestion_control = hybla \n\
# for low-latency network, use cubic instead \n\
# net.ipv4.tcp_congestion_control = cubic \n\
" | sed -e 's/^\s\+//g' | tee -a /etc/sysctl.conf && \
mkdir -p /etc/security && \
echo -e " \n\
* soft nofile 51200 \n\
* hard nofile 51200 \n\
" | sed -e 's/^\s\+//g' | tee -a /etc/security/limits.conf
ENTRYPOINT [ "dumb-init", "/opt/amnezia/start.sh" ]
CMD [ "" ]

View File

@@ -1,26 +0,0 @@
mkdir -p /opt/amnezia/awg
cd /opt/amnezia/awg
WIREGUARD_SERVER_PRIVATE_KEY=$(wg genkey)
echo $WIREGUARD_SERVER_PRIVATE_KEY > /opt/amnezia/awg/wireguard_server_private_key.key
WIREGUARD_SERVER_PUBLIC_KEY=$(echo $WIREGUARD_SERVER_PRIVATE_KEY | wg pubkey)
echo $WIREGUARD_SERVER_PUBLIC_KEY > /opt/amnezia/awg/wireguard_server_public_key.key
WIREGUARD_PSK=$(wg genpsk)
echo $WIREGUARD_PSK > /opt/amnezia/awg/wireguard_psk.key
cat > /opt/amnezia/awg/wg0.conf <<EOF
[Interface]
PrivateKey = $WIREGUARD_SERVER_PRIVATE_KEY
Address = $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR
ListenPort = $AWG_SERVER_PORT
Jc = $JUNK_PACKET_COUNT
Jmin = $JUNK_PACKET_MIN_SIZE
Jmax = $JUNK_PACKET_MAX_SIZE
S1 = $INIT_PACKET_JUNK_SIZE
S2 = $RESPONSE_PACKET_JUNK_SIZE
H1 = $INIT_PACKET_MAGIC_HEADER
H2 = $RESPONSE_PACKET_MAGIC_HEADER
H3 = $UNDERLOAD_PACKET_MAGIC_HEADER
H4 = $TRANSPORT_PACKET_MAGIC_HEADER
EOF

View File

@@ -1,18 +0,0 @@
# Run container
sudo docker run -d \
--log-driver none \
--restart always \
--privileged \
--cap-add=NET_ADMIN \
--cap-add=SYS_MODULE \
-p $AWG_SERVER_PORT:$AWG_SERVER_PORT/udp \
-v /lib/modules:/lib/modules \
--sysctl="net.ipv4.conf.all.src_valid_mark=1" \
--name $CONTAINER_NAME \
$CONTAINER_NAME
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
# Prevent to route packets outside of the container in case if server behind of the NAT
#sudo docker exec -i $CONTAINER_NAME sh -c "ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up"

View File

@@ -1,28 +0,0 @@
#!/bin/bash
# This scripts copied from Amnezia client to Docker container to /opt/amnezia and launched every time container starts
echo "Container startup"
#ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up
# kill daemons in case of restart
wg-quick down /opt/amnezia/awg/wg0.conf
# start daemons if configured
if [ -f /opt/amnezia/awg/wg0.conf ]; then (wg-quick up /opt/amnezia/awg/wg0.conf); fi
# Allow traffic on the TUN interface.
iptables -A INPUT -i wg0 -j ACCEPT
iptables -A FORWARD -i wg0 -j ACCEPT
iptables -A OUTPUT -o wg0 -j ACCEPT
# Allow forwarding traffic only from the VPN.
iptables -A FORWARD -i wg0 -o eth0 -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -i wg0 -o eth1 -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -o eth1 -j MASQUERADE
tail -f /dev/null

View File

@@ -1,20 +0,0 @@
[Interface]
Address = $WIREGUARD_CLIENT_IP/32
DNS = $PRIMARY_DNS, $SECONDARY_DNS
PrivateKey = $WIREGUARD_CLIENT_PRIVATE_KEY
Jc = $JUNK_PACKET_COUNT
Jmin = $JUNK_PACKET_MIN_SIZE
Jmax = $JUNK_PACKET_MAX_SIZE
S1 = $INIT_PACKET_JUNK_SIZE
S2 = $RESPONSE_PACKET_JUNK_SIZE
H1 = $INIT_PACKET_MAGIC_HEADER
H2 = $RESPONSE_PACKET_MAGIC_HEADER
H3 = $UNDERLOAD_PACKET_MAGIC_HEADER
H4 = $TRANSPORT_PACKET_MAGIC_HEADER
[Peer]
PublicKey = $WIREGUARD_SERVER_PUBLIC_KEY
PresharedKey = $WIREGUARD_PSK
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = $SERVER_IP_ADDRESS:$AWG_SERVER_PORT
PersistentKeepalive = 25

View File

@@ -1 +1 @@
sudo docker build --no-cache --pull -t $CONTAINER_NAME $DOCKERFILE_FOLDER --build-arg SERVER_ARCH=$(uname -m)
sudo docker build -t $CONTAINER_NAME $DOCKERFILE_FOLDER --build-arg SERVER_ARCH=$(uname -m)

View File

@@ -1,6 +1,5 @@
if which apt-get > /dev/null 2>&1; then LOCK_FILE="/var/lib/dpkg/lock-frontend";\
elif which dnf > /dev/null 2>&1; then LOCK_FILE="/var/run/dnf.pid";\
elif which yum > /dev/null 2>&1; then LOCK_FILE="/var/run/yum.pid";\
elif which pacman > /dev/null 2>&1; then LOCK_FILE="/var/lib/pacman/db.lck";\
else echo "Packet manager not found"; echo "Internal error"; exit 1; fi;\
if command -v fuser > /dev/null 2>&1; then sudo fuser $LOCK_FILE 2>/dev/null; else echo "fuser not installed"; fi
if command -v fuser > /dev/null 2>&1; then sudo fuser $LOCK_FILE 2>/dev/null; else echo "fuser not installed"; fi

View File

@@ -1,20 +1,20 @@
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian";\
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora";\
elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos";\
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="--noconfirm -S"; check_pkgs="> /dev/null 2>&1"; docker_pkg="docker"; dist="archlinux";\
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); docker_pkg="docker.io"; dist="debian";\
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); docker_pkg="docker"; dist="fedora";\
elif which yum > /dev/null 2>&1; then pm=$(which yum); docker_pkg="docker"; dist="centos";\
else echo "Packet manager not found"; exit 1; fi;\
echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, Check pkgs command: $check_pkgs, Docker pkg: $docker_pkg";\
echo "Dist: $dist, Packet manager: $pm, Docker pkg: $docker_pkg";\
if [ "$dist" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive; fi;\
if ! command -v sudo > /dev/null 2>&1; then $pm $check_pkgs; $pm $silent_inst sudo; fi;\
if ! command -v fuser > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst psmisc; fi;\
if ! command -v lsof > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst lsof; fi;\
if ! command -v docker > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst $docker_pkg;\
if [ "$dist" = "fedora" ] || [ "$dist" = "centos" ] || [ "$dist" = "debian" ]; then sudo systemctl enable docker && sudo systemctl start docker; fi;\
if ! command -v sudo > /dev/null 2>&1; then $pm update -yq; $pm install -yq sudo; fi;\
if ! command -v fuser > /dev/null 2>&1; then $pm install -yq psmisc; fi;\
if ! command -v lsof > /dev/null 2>&1; then $pm install -yq lsof; fi;\
if ! command -v docker > /dev/null 2>&1; then $pm update -yq; $pm install -yq $docker_pkg;\
if [ "$dist" = "fedora" ] || [ "$dist" = "debian" ]; then sudo systemctl enable docker && sudo systemctl start docker; fi;\
fi;\
if [ "$dist" = "debian" ]; then \
docker_service=$(systemctl list-units --full --all | grep docker.service | grep -v inactive | grep -v dead | grep -v failed);\
if [ -z "$docker_service" ]; then sudo $pm $check_pkgs; sudo $pm $silent_inst curl $docker_pkg; fi;\
if [ -z "$docker_service" ]; then sudo $pm update -yq; sudo $pm install -yq curl $docker_pkg; fi;\
sleep 3 && sudo systemctl start docker && sleep 3;\
fi;\
if ! command -v sudo > /dev/null 2>&1; then echo "Failed to install Docker"; exit 1; fi;\
if ! command -v sudo > /dev/null 2>&1; then echo "Failed to install Docker";exit 1;fi;\
docker --version

View File

@@ -233,6 +233,10 @@ QString Settings::routeModeString(RouteMode mode) const
Settings::RouteMode Settings::routeMode() const
{
// TODO implement for mobiles
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
return RouteMode::VpnAllSites;
#endif
return static_cast<RouteMode>(m_settings.value("Conf/routeMode", 0).toInt());
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +0,0 @@
<RCC>
<qresource prefix="/translations">
@QM_FILE_LIST@
</qresource>
</RCC>

View File

@@ -19,8 +19,23 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
Qt::QueuedConnection);
connect(this, &ConnectionController::disconnectFromVpn, m_vpnConnection.get(), &VpnConnection::disconnectFromVpn,
Qt::QueuedConnection);
}
m_state = Vpn::ConnectionState::Disconnected;
ConnectionController::~ConnectionController()
{
// todo use ConnectionController instead of using m_vpnConnection directly
#ifdef AMNEZIA_DESKTOP
if (m_vpnConnection->connectionState() != Vpn::ConnectionState::Disconnected) {
m_vpnConnection->disconnectFromVpn();
for (int i = 0; i < 50; i++) {
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
QThread::msleep(100);
if (m_vpnConnection->isDisconnected()) {
break;
}
}
}
#endif
}
void ConnectionController::openConnection()
@@ -55,8 +70,6 @@ QString ConnectionController::getLastConnectionError()
void ConnectionController::onConnectionStateChanged(Vpn::ConnectionState state)
{
m_state = state;
m_isConnected = false;
m_connectionStateText = tr("Connection...");
switch (state) {
@@ -113,17 +126,6 @@ void ConnectionController::onCurrentContainerUpdated()
}
}
void ConnectionController::onTranslationsUpdated()
{
// get translated text of current state
onConnectionStateChanged(getCurrentConnectionState());
}
Vpn::ConnectionState ConnectionController::getCurrentConnectionState()
{
return m_state;
}
QString ConnectionController::connectionStateText() const
{
return m_connectionStateText;

View File

@@ -19,7 +19,7 @@ public:
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<VpnConnection> &vpnConnection, QObject *parent = nullptr);
~ConnectionController() = default;
~ConnectionController();
bool isConnected() const;
bool isConnectionInProgress() const;
@@ -34,8 +34,6 @@ public slots:
void onCurrentContainerUpdated();
void onTranslationsUpdated();
signals:
void connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig);
@@ -46,8 +44,6 @@ signals:
void reconnectWithUpdatedContainer(const QString &message);
private:
Vpn::ConnectionState getCurrentConnectionState();
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
@@ -56,8 +52,6 @@ private:
bool m_isConnected = false;
bool m_isConnectionInProgress = false;
QString m_connectionStateText = tr("Connect");
Vpn::ConnectionState m_state;
};
#endif // CONNECTIONCONTROLLER_H

View File

@@ -8,9 +8,7 @@
#include <QImage>
#include <QStandardPaths>
#include "configurators/cloak_configurator.h"
#include "configurators/openvpn_configurator.h"
#include "configurators/shadowsocks_configurator.h"
#include "configurators/wireguard_configurator.h"
#include "core/errorstrings.h"
#include "systemController.h"
@@ -21,13 +19,11 @@
ExportController::ExportController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const std::shared_ptr<Settings> &settings,
const std::shared_ptr<VpnConfigurator> &configurator, QObject *parent)
: QObject(parent),
m_serversModel(serversModel),
m_containersModel(containersModel),
m_clientManagementModel(clientManagementModel),
m_settings(settings),
m_configurator(configurator)
{
@@ -79,12 +75,13 @@ void ExportController::generateFullAccessConfigAndroid()
}
#endif
void ExportController::generateConnectionConfig(const QString &clientName)
void ExportController::generateConnectionConfig()
{
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getCurrentlyProcessedServerCredentials();
ServerCredentials credentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QModelIndex containerModelIndex = m_containersModel->index(container);
@@ -96,25 +93,17 @@ void ExportController::generateConnectionConfig(const QString &clientName)
for (Proto protocol : ContainerProps::protocolsForContainer(container)) {
QJsonObject protocolConfig = m_settings->protocolConfig(serverIndex, container, protocol);
QString clientId;
QString vpnConfig = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, protocol,
clientId, &errorCode);
QString vpnConfig =
m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, protocol, &errorCode);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
protocolConfig.insert(config_key::last_config, vpnConfig);
containerConfig.insert(ProtocolProps::protoToString(protocol), protocolConfig);
if (protocol == Proto::OpenVpn || protocol == Proto::Awg || protocol == Proto::WireGuard) {
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
}
}
QJsonObject config = m_settings->server(serverIndex); // todo change to servers_model
QJsonObject config = m_settings->server(serverIndex);
if (!errorCode) {
config.remove(config_key::userName);
config.remove(config_key::password);
@@ -137,127 +126,7 @@ void ExportController::generateConnectionConfig(const QString &clientName)
emit exportConfigChanged();
}
void ExportController::generateOpenVpnConfig(const QString &clientName)
{
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getCurrentlyProcessedServerCredentials();
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QModelIndex containerModelIndex = m_containersModel->index(container);
QJsonObject containerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole));
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError;
QString clientId;
QString config = m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig,
clientId, &errorCode);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, config);
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) {
m_config.append(line + "\n");
}
m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8());
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
emit exportConfigChanged();
}
void ExportController::generateWireGuardConfig(const QString &clientName)
{
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getCurrentlyProcessedServerCredentials();
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QModelIndex containerModelIndex = m_containersModel->index(container);
QJsonObject containerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole));
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
QString clientId;
ErrorCode errorCode = ErrorCode::NoError;
QString config = m_configurator->wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig,
clientId, &errorCode);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::WireGuard, config);
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) {
m_config.append(line + "\n");
}
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_config.toUtf8(), qrcodegen::QrCode::Ecc::LOW);
m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
emit exportConfigChanged();
}
void ExportController::generateShadowSocksConfig()
{
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QModelIndex containerModelIndex = m_containersModel->index(container);
QJsonObject containerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole));
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError;
QString config = m_configurator->shadowSocksConfigurator->genShadowSocksConfig(credentials, container,
containerConfig, &errorCode);
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::ShadowSocks, config);
QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = QString(QJsonDocument(configJson).toJson()).replace("\r", "").split("\n");
for (const QString &line : lines) {
m_config.append(line + "\n");
}
m_nativeConfigString =
QString("%1:%2@%3:%4")
.arg(configJson.value("method").toString(), configJson.value("password").toString(),
configJson.value("server").toString(), configJson.value("server_port").toString());
m_nativeConfigString = "ss://" + m_nativeConfigString.toUtf8().toBase64();
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_nativeConfigString.toUtf8(), qrcodegen::QrCode::Ecc::LOW);
m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
emit exportConfigChanged();
}
void ExportController::generateCloakConfig()
void ExportController::generateOpenVpnConfig()
{
clearPreviousConfig();
@@ -273,19 +142,47 @@ void ExportController::generateCloakConfig()
ErrorCode errorCode = ErrorCode::NoError;
QString config =
m_configurator->cloakConfigurator->genCloakConfig(credentials, container, containerConfig, &errorCode);
m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, &errorCode);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::Cloak, config);
QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object();
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, config);
configJson.remove(config_key::transport_proto);
configJson.insert("ProxyMethod", "shadowsocks");
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) {
m_config.append(line + "\n");
}
QStringList lines = QString(QJsonDocument(configJson).toJson()).replace("\r", "").split("\n");
emit exportConfigChanged();
}
void ExportController::generateWireGuardConfig()
{
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QModelIndex containerModelIndex = m_containersModel->index(container);
QJsonObject containerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole));
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError;
QString config = m_configurator->wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig,
&errorCode);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::WireGuard, config);
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) {
m_config.append(line + "\n");
}
@@ -298,11 +195,6 @@ QString ExportController::getConfig()
return m_config;
}
QString ExportController::getNativeConfigString()
{
return m_nativeConfigString;
}
QList<QString> ExportController::getQrCodes()
{
return m_qrCodes;
@@ -313,30 +205,6 @@ void ExportController::exportConfig(const QString &fileName)
SystemController::saveFile(fileName, m_config);
}
void ExportController::updateClientManagementModel(const DockerContainer container, ServerCredentials credentials)
{
ErrorCode errorCode = m_clientManagementModel->updateModel(container, credentials);
if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode));
}
}
void ExportController::revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials)
{
ErrorCode errorCode = m_clientManagementModel->revokeClient(row, container, credentials);
if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode));
}
}
void ExportController::renameClient(const int row, const QString &clientName, const DockerContainer container, ServerCredentials credentials)
{
ErrorCode errorCode = m_clientManagementModel->renameClient(row, clientName, container, credentials);
if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode));
}
}
QList<QString> ExportController::generateQrCodeImageSeries(const QByteArray &data)
{
double k = 850;
@@ -351,7 +219,7 @@ QList<QString> ExportController::generateQrCodeImageSeries(const QByteArray &dat
QByteArray ba = chunk.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(ba, qrcodegen::QrCode::Ecc::LOW);
QString svg = QString::fromStdString(toSvgString(qr, 1));
QString svg = QString::fromStdString(toSvgString(qr, 0));
chunks.append(svgToBase64(svg));
}
@@ -371,6 +239,5 @@ int ExportController::getQrCodesCount()
void ExportController::clearPreviousConfig()
{
m_config.clear();
m_nativeConfigString.clear();
m_qrCodes.clear();
}

View File

@@ -6,7 +6,6 @@
#include "configurators/vpn_configurator.h"
#include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
#include "ui/models/clientManagementModel.h"
#ifdef Q_OS_ANDROID
#include "platforms/android/authResultReceiver.h"
#endif
@@ -17,36 +16,27 @@ class ExportController : public QObject
public:
explicit ExportController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const std::shared_ptr<Settings> &settings,
const std::shared_ptr<VpnConfigurator> &configurator, QObject *parent = nullptr);
Q_PROPERTY(QList<QString> qrCodes READ getQrCodes NOTIFY exportConfigChanged)
Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY exportConfigChanged)
Q_PROPERTY(QString config READ getConfig NOTIFY exportConfigChanged)
Q_PROPERTY(QString nativeConfigString READ getNativeConfigString NOTIFY exportConfigChanged)
public slots:
void generateFullAccessConfig();
#if defined(Q_OS_ANDROID)
void generateFullAccessConfigAndroid();
#endif
void generateConnectionConfig(const QString &clientName);
void generateOpenVpnConfig(const QString &clientName);
void generateWireGuardConfig(const QString &clientName);
void generateShadowSocksConfig();
void generateCloakConfig();
void generateConnectionConfig();
void generateOpenVpnConfig();
void generateWireGuardConfig();
QString getConfig();
QString getNativeConfigString();
QList<QString> getQrCodes();
void exportConfig(const QString &fileName);
void updateClientManagementModel(const DockerContainer container, ServerCredentials credentials);
void revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials);
void renameClient(const int row, const QString &clientName, const DockerContainer container, ServerCredentials credentials);
signals:
void generateConfig(int type);
void exportErrorOccurred(const QString &errorMessage);
@@ -65,12 +55,10 @@ private:
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel;
std::shared_ptr<Settings> m_settings;
std::shared_ptr<VpnConfigurator> m_configurator;
QString m_config;
QString m_nativeConfigString;
QList<QString> m_qrCodes;
#ifdef Q_OS_ANDROID

View File

@@ -144,6 +144,8 @@ void ImportController::importConfig()
if (credentials.isValid() || m_config.contains(config_key::containers)) {
m_serversModel->addServer(m_config);
m_serversModel->setDefaultServerIndex(m_serversModel->getServersCount() - 1);
emit importFinished();
} else {
qDebug() << "Failed to import profile";
@@ -212,79 +214,21 @@ QJsonObject ImportController::extractOpenVpnConfig(const QString &data)
QJsonObject ImportController::extractWireGuardConfig(const QString &data)
{
QMap<QString, QString> configMap;
auto configByLines = data.split("\n");
for (const QString &line : configByLines) {
QString trimmedLine = line.trimmed();
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
continue;
} else {
QStringList parts = trimmedLine.split(" = ");
if (parts.count() == 2) {
configMap[parts.at(0).trimmed()] = parts.at(1).trimmed();
}
}
}
QJsonObject lastConfig;
lastConfig[config_key::config] = data;
const static QRegularExpression hostNameAndPortRegExp("Endpoint = (.*):([0-9]*)");
const static QRegularExpression hostNameAndPortRegExp("Endpoint = (.*)(?::([0-9]*))?");
QRegularExpressionMatch hostNameAndPortMatch = hostNameAndPortRegExp.match(data);
QString hostName;
QString port;
if (hostNameAndPortMatch.hasCaptured(1)) {
hostName = hostNameAndPortMatch.captured(1);
} else {
qDebug() << "Failed to import profile";
emit importErrorOccurred(errorString(ErrorCode::ImportInvalidConfigError));
}
} /*else {
qDebug() << "send error?"
}*/
if (hostNameAndPortMatch.hasCaptured(2)) {
port = hostNameAndPortMatch.captured(2);
} else {
port = protocols::wireguard::defaultPort;
}
lastConfig[config_key::hostName] = hostName;
lastConfig[config_key::port] = port.toInt();
// if (!configMap.value("PrivateKey").isEmpty() && !configMap.value("Address").isEmpty()
// && !configMap.value("PresharedKey").isEmpty() && !configMap.value("PublicKey").isEmpty()) {
lastConfig[config_key::client_priv_key] = configMap.value("PrivateKey");
lastConfig[config_key::client_ip] = configMap.value("Address");
lastConfig[config_key::psk_key] = configMap.value("PresharedKey");
lastConfig[config_key::server_pub_key] = configMap.value("PublicKey");
// } else {
// qDebug() << "Failed to import profile";
// emit importErrorOccurred(errorString(ErrorCode::ImportInvalidConfigError));
// return QJsonObject();
// }
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configMap.value("AllowedIPs").split(","));
lastConfig[config_key::allowed_ips] = allowedIpsJsonArray;
QString protocolName = "wireguard";
if (!configMap.value(config_key::junkPacketCount).isEmpty()
&& !configMap.value(config_key::junkPacketMinSize).isEmpty()
&& !configMap.value(config_key::junkPacketMaxSize).isEmpty()
&& !configMap.value(config_key::initPacketJunkSize).isEmpty()
&& !configMap.value(config_key::responsePacketJunkSize).isEmpty()
&& !configMap.value(config_key::initPacketMagicHeader).isEmpty()
&& !configMap.value(config_key::responsePacketMagicHeader).isEmpty()
&& !configMap.value(config_key::underloadPacketMagicHeader).isEmpty()
&& !configMap.value(config_key::transportPacketMagicHeader).isEmpty()) {
lastConfig[config_key::junkPacketCount] = configMap.value(config_key::junkPacketCount);
lastConfig[config_key::junkPacketMinSize] = configMap.value(config_key::junkPacketMinSize);
lastConfig[config_key::junkPacketMaxSize] = configMap.value(config_key::junkPacketMaxSize);
lastConfig[config_key::initPacketJunkSize] = configMap.value(config_key::initPacketJunkSize);
lastConfig[config_key::responsePacketJunkSize] = configMap.value(config_key::responsePacketJunkSize);
lastConfig[config_key::initPacketMagicHeader] = configMap.value(config_key::initPacketMagicHeader);
lastConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader);
lastConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader);
lastConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader);
protocolName = "awg";
}
QJsonObject wireguardConfig;
@@ -294,15 +238,15 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
wireguardConfig[config_key::transport_proto] = "udp";
QJsonObject containers;
containers.insert(config_key::container, QJsonValue("amnezia-" + protocolName));
containers.insert(protocolName, QJsonValue(wireguardConfig));
containers.insert(config_key::container, QJsonValue("amnezia-wireguard"));
containers.insert(config_key::wireguard, QJsonValue(wireguardConfig));
QJsonArray arr;
arr.push_back(containers);
QJsonObject config;
config[config_key::containers] = arr;
config[config_key::defaultContainer] = "amnezia-" + protocolName;
config[config_key::defaultContainer] = "amnezia-wireguard";
config[config_key::description] = m_settings->nextAvailableServerName();
const static QRegularExpression dnsRegExp(

View File

@@ -5,7 +5,6 @@
#include <QEventLoop>
#include <QJsonObject>
#include <QStandardPaths>
#include <QRandomGenerator>
#include "core/errorstrings.h"
#include "core/servercontroller.h"
@@ -74,38 +73,6 @@ void InstallController::install(DockerContainer container, int port, TransportPr
containerConfig.insert(config_key::transport_proto,
ProtocolProps::transportProtoToString(transportProto, protocol));
if (container == DockerContainer::Awg) {
QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(3, 10));
QString junkPacketMinSize = QString::number(50);
QString junkPacketMaxSize = QString::number(1000);
QString initPacketJunkSize = QString::number(QRandomGenerator::global()->bounded(15, 150));
QString responsePacketJunkSize = QString::number(QRandomGenerator::global()->bounded(15, 150));
QSet<QString> headersValue;
while (headersValue.size() != 4) {
auto max = (std::numeric_limits<qint32>::max)();
headersValue.insert(QString::number(QRandomGenerator::global()->bounded(1, max)));
}
auto headersValueList = headersValue.values();
QString initPacketMagicHeader = headersValueList.at(0);
QString responsePacketMagicHeader = headersValueList.at(1);
QString underloadPacketMagicHeader = headersValueList.at(2);
QString transportPacketMagicHeader = headersValueList.at(3);
containerConfig[config_key::junkPacketCount] = junkPacketCount;
containerConfig[config_key::junkPacketMinSize] = junkPacketMinSize;
containerConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize;
containerConfig[config_key::initPacketJunkSize] = initPacketJunkSize;
containerConfig[config_key::responsePacketJunkSize] = responsePacketJunkSize;
containerConfig[config_key::initPacketMagicHeader] = initPacketMagicHeader;
containerConfig[config_key::responsePacketMagicHeader] = responsePacketMagicHeader;
containerConfig[config_key::underloadPacketMagicHeader] = underloadPacketMagicHeader;
containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader;
}
if (container == DockerContainer::Sftp) {
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
containerConfig.insert(config_key::password, Utils::getRandomString(10));
@@ -140,9 +107,10 @@ void InstallController::installServer(DockerContainer container, QJsonObject &co
if (!installedContainers.contains(container)) {
errorCode = serverController.setupContainer(m_currentlyInstalledServerCredentials, container, config);
installedContainers.insert(container, config);
finishMessage = tr("%1 installed successfully. ").arg(ContainerProps::containerHumanNames().value(container));
finishMessage = ContainerProps::containerHumanNames().value(container) + tr(" installed successfully. ");
} else {
finishMessage = tr("%1 is already installed on the server. ").arg(ContainerProps::containerHumanNames().value(container));
finishMessage =
ContainerProps::containerHumanNames().value(container) + tr(" is already installed on the server. ");
}
if (installedContainers.size() > 1) {
finishMessage += tr("\nAdded containers that were already installed on the server");
@@ -165,6 +133,7 @@ void InstallController::installServer(DockerContainer container, QJsonObject &co
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
m_serversModel->addServer(server);
m_serversModel->setDefaultServerIndex(m_serversModel->getServersCount() - 1);
emit installServerFinished(finishMessage);
return;
@@ -190,9 +159,10 @@ void InstallController::installContainer(DockerContainer container, QJsonObject
if (!installedContainers.contains(container)) {
errorCode = serverController.setupContainer(serverCredentials, container, config);
installedContainers.insert(container, config);
finishMessage = tr("%1 installed successfully. ").arg(ContainerProps::containerHumanNames().value(container));
finishMessage = ContainerProps::containerHumanNames().value(container) + tr(" installed successfully. ");
} else {
finishMessage = tr("%1 is already installed on the server. ").arg(ContainerProps::containerHumanNames().value(container));
finishMessage =
ContainerProps::containerHumanNames().value(container) + tr(" is already installed on the server. ");
}
bool isInstalledContainerAddedToGui = false;
@@ -307,7 +277,7 @@ void InstallController::removeCurrentlyProcessedServer()
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
m_serversModel->removeServer();
emit removeCurrentlyProcessedServerFinished(tr("Server '%1' was removed").arg(serverName));
emit removeCurrentlyProcessedServerFinished(tr("Server '") + serverName + tr("' was removed"));
}
void InstallController::removeAllContainers()
@@ -317,7 +287,7 @@ void InstallController::removeAllContainers()
ErrorCode errorCode = m_containersModel->removeAllContainers();
if (errorCode == ErrorCode::NoError) {
emit removeAllContainersFinished(tr("All containers from server '%1' have been removed").arg(serverName));
emit removeAllContainersFinished(tr("All containers from server '") + serverName + ("' have been removed"));
return;
}
emit installationErrorOccurred(errorString(errorCode));
@@ -333,8 +303,8 @@ void InstallController::removeCurrentlyProcessedContainer()
ErrorCode errorCode = m_containersModel->removeCurrentlyProcessedContainer();
if (errorCode == ErrorCode::NoError) {
emit removeCurrentlyProcessedContainerFinished(tr("%1 has been removed from the server '%2'").arg(containerName).arg(serverName));
emit removeCurrentlyProcessedContainerFinished(containerName + tr(" has been removed from the server '")
+ serverName + "'");
return;
}
emit installationErrorOccurred(errorString(errorCode));
@@ -504,9 +474,8 @@ void InstallController::addEmptyServer()
server.insert(config_key::port, m_currentlyInstalledServerCredentials.port);
server.insert(config_key::description, m_settings->nextAvailableServerName());
server.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
m_serversModel->addServer(server);
m_serversModel->setDefaultServerIndex(m_serversModel->getServersCount() - 1);
emit installServerFinished(tr("Server added successfully"));
}

View File

@@ -157,8 +157,3 @@ void PageController::setTriggeredBtConnectButton(bool trigger)
{
m_isTriggeredByConnectButton = trigger;
}
void PageController::closeApplication()
{
qApp->quit();
}

View File

@@ -49,11 +49,8 @@ namespace PageLoader
PageProtocolShadowSocksSettings,
PageProtocolCloakSettings,
PageProtocolWireGuardSettings,
PageProtocolAwgSettings,
PageProtocolIKev2Settings,
PageProtocolRaw,
PageShareFullAccess
PageProtocolRaw
};
Q_ENUM_NS(PageEnum)
@@ -87,11 +84,10 @@ public slots:
void drawerOpen();
void drawerClose();
bool isTriggeredByConnectButton();
void setTriggeredBtConnectButton(bool trigger);
void closeApplication();
signals:
void goToPage(PageLoader::PageEnum page, bool slide = true);
void goToStartPage();

View File

@@ -22,7 +22,7 @@ SettingsController::SettingsController(const QSharedPointer<ServersModel> &serve
m_languageModel(languageModel),
m_settings(settings)
{
m_appVersion = QString("%1: %2 (%3)").arg(tr("Software version"), QString(APP_VERSION), __DATE__);
m_appVersion = QString("%1: %2 (%3)").arg(tr("Software version"), QString(APP_MAJOR_VERSION), __DATE__);
#ifdef Q_OS_ANDROID
if (!m_settings->isScreenshotsEnabled()) {
@@ -193,4 +193,4 @@ void SettingsController::toggleScreenshotsEnabled(bool enable)
}
});
#endif
}
}

View File

@@ -64,7 +64,7 @@ void SitesController::addSite(QString hostname)
QHostInfo::lookupHost(hostname, this, resolveCallback);
}
emit finished(tr("New site added: %1").arg(hostname));
emit finished(tr("New site added: ") + hostname);
}
void SitesController::removeSite(int index)
@@ -77,7 +77,7 @@ void SitesController::removeSite(int index)
Q_ARG(QStringList, QStringList() << hostname));
QMetaObject::invokeMethod(m_vpnConnection.get(), "flushDns", Qt::QueuedConnection);
emit finished(tr("Site removed: %1").arg(hostname));
emit finished(tr("Site removed: ") + hostname);
}
void SitesController::importSites(const QString &fileName, bool replaceExisting)
@@ -85,19 +85,19 @@ void SitesController::importSites(const QString &fileName, bool replaceExisting)
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
emit errorOccurred(tr("Can't open file: %1").arg(fileName));
emit errorOccurred(tr("Can't open file: ") + fileName);
return;
}
QByteArray jsonData = file.readAll();
QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonData);
if (jsonDocument.isNull()) {
emit errorOccurred(tr("Failed to parse JSON data from file: %1").arg(fileName));
emit errorOccurred(tr("Failed to parse JSON data from file: ") + fileName);
return;
}
if (!jsonDocument.isArray()) {
emit errorOccurred(tr("The JSON data is not an array in file: %1").arg(fileName));
emit errorOccurred(tr("The JSON data is not an array in file: ") + fileName);
return;
}

View File

@@ -1,373 +1,104 @@
#include "clientManagementModel.h"
#include <QJsonDocument>
#include <QJsonObject>
#include "core/servercontroller.h"
#include "logger.h"
namespace
ClientManagementModel::ClientManagementModel(QObject *parent) : QAbstractListModel(parent)
{
Logger logger("ClientManagementModel");
namespace configKey {
constexpr char clientId[] = "clientId";
constexpr char clientName[] = "clientName";
constexpr char container[] = "container";
constexpr char userData[] = "userData";
}
}
ClientManagementModel::ClientManagementModel(std::shared_ptr<Settings> settings, QObject *parent)
: m_settings(settings), QAbstractListModel(parent)
void ClientManagementModel::clearData()
{
beginResetModel();
m_content.clear();
endResetModel();
}
void ClientManagementModel::setContent(const QVector<QVariant> &data)
{
beginResetModel();
m_content = data;
endResetModel();
}
QJsonObject ClientManagementModel::getContent(amnezia::Proto protocol)
{
QJsonObject clientsTable;
for (const auto &item : m_content) {
if (protocol == amnezia::Proto::OpenVpn) {
clientsTable[item.toJsonObject()["openvpnCertId"].toString()] = item.toJsonObject();
} else if (protocol == amnezia::Proto::WireGuard) {
clientsTable[item.toJsonObject()["wireguardPublicKey"].toString()] = item.toJsonObject();
}
}
return clientsTable;
}
int ClientManagementModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return static_cast<int>(m_clientsTable.size());
return static_cast<int>(m_content.size());
}
QVariant ClientManagementModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(m_clientsTable.size())) {
if (!index.isValid() || index.row() < 0
|| index.row() >= static_cast<int>(m_content.size())) {
return QVariant();
}
auto client = m_clientsTable.at(index.row()).toObject();
auto userData = client.value(configKey::userData).toObject();
switch (role) {
case ClientNameRole: return userData.value(configKey::clientName).toString();
if (role == NameRole) {
return m_content[index.row()].toJsonObject()["clientName"].toString();
} else if (role == OpenVpnCertIdRole) {
return m_content[index.row()].toJsonObject()["openvpnCertId"].toString();
} else if (role == OpenVpnCertDataRole) {
return m_content[index.row()].toJsonObject()["openvpnCertData"].toString();
} else if (role == WireGuardPublicKey) {
return m_content[index.row()].toJsonObject()["wireguardPublicKey"].toString();
}
return QVariant();
}
ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCredentials credentials)
void ClientManagementModel::setData(const QModelIndex &index, QVariant data, int role)
{
beginResetModel();
m_clientsTable = QJsonArray();
ServerController serverController(m_settings);
ErrorCode error = ErrorCode::NoError;
const QString clientsTableFile =
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
const QByteArray clientsTableString =
serverController.getTextFileFromContainer(container, credentials, clientsTableFile, &error);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the clientsTable file from the server";
endResetModel();
return error;
if (!index.isValid() || index.row() < 0
|| index.row() >= static_cast<int>(m_content.size())) {
return;
}
m_clientsTable = QJsonDocument::fromJson(clientsTableString).array();
if (m_clientsTable.isEmpty()) {
int count = 0;
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks
|| container == DockerContainer::Cloak) {
error = getOpenVpnClients(serverController, container, credentials, count);
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
error = getWireGuardClients(serverController, container, credentials, count);
}
if (error != ErrorCode::NoError) {
endResetModel();
return error;
}
const QByteArray newClientsTableString = QJsonDocument(m_clientsTable).toJson();
if (clientsTableString != newClientsTableString) {
error = serverController.uploadTextFileToContainer(container, credentials, newClientsTableString,
clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
}
}
auto client = m_content[index.row()].toJsonObject();
if (role == NameRole) {
client["clientName"] = data.toString();
} else if (role == OpenVpnCertIdRole) {
client["openvpnCertId"] = data.toString();
} else if (role == OpenVpnCertDataRole) {
client["openvpnCertData"] = data.toString();
} else if (role == WireGuardPublicKey) {
client["wireguardPublicKey"] = data.toString();
} else {
return;
}
if (m_content[index.row()] != client) {
m_content[index.row()] = client;
emit dataChanged(index, index);
}
endResetModel();
return error;
}
ErrorCode ClientManagementModel::getOpenVpnClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count)
bool ClientManagementModel::removeRows(int row)
{
ErrorCode error = ErrorCode::NoError;
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
return ErrorCode::NoError;
};
const QString getOpenVpnClientsList =
"sudo docker exec -i $CONTAINER_NAME bash -c 'ls /opt/amnezia/openvpn/pki/issued'";
QString script = serverController.replaceVars(getOpenVpnClientsList,
serverController.genVarsForScript(credentials, container));
error = serverController.runScript(credentials, script, cbReadStdOut);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to retrieve the list of issued certificates on the server";
return error;
}
if (!stdOut.isEmpty()) {
QStringList certsIds = stdOut.split("\n", Qt::SkipEmptyParts);
certsIds.removeAll("AmneziaReq.crt");
for (auto &openvpnCertId : certsIds) {
openvpnCertId.replace(".crt", "");
if (!isClientExists(openvpnCertId)) {
QJsonObject client;
client[configKey::clientId] = openvpnCertId;
QJsonObject userData;
userData[configKey::clientName] = QString("Client %1").arg(count);
client[configKey::userData] = userData;
m_clientsTable.push_back(client);
count++;
}
}
}
return error;
}
ErrorCode ClientManagementModel::getWireGuardClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count)
{
ErrorCode error = ErrorCode::NoError;
const QString wireGuardConfigFile =
QString("opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg");
const QString wireguardConfigString =
serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, &error);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the wg conf file from the server";
return error;
}
auto configLines = wireguardConfigString.split("\n", Qt::SkipEmptyParts);
QStringList wireguardKeys;
for (const auto &line : configLines) {
auto configPair = line.split(" = ", Qt::SkipEmptyParts);
if (configPair.front() == "PublicKey") {
wireguardKeys.push_back(configPair.back());
}
}
for (auto &wireguardKey : wireguardKeys) {
if (!isClientExists(wireguardKey)) {
QJsonObject client;
client[configKey::clientId] = wireguardKey;
QJsonObject userData;
userData[configKey::clientName] = QString("Client %1").arg(count);
client[configKey::userData] = userData;
m_clientsTable.push_back(client);
count++;
}
}
return error;
}
bool ClientManagementModel::isClientExists(const QString &clientId)
{
for (const QJsonValue &value : qAsConst(m_clientsTable)) {
if (value.isObject()) {
QJsonObject obj = value.toObject();
if (obj.contains(configKey::clientId) && obj[configKey::clientId].toString() == clientId) {
return true;
}
}
}
return false;
}
ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QString &clientName,
const DockerContainer container, ServerCredentials credentials)
{
ErrorCode error;
error = updateModel(container, credentials);
if (error != ErrorCode::NoError) {
return error;
}
for (int i = 0; i < m_clientsTable.size(); i++) {
if (m_clientsTable.at(i).toObject().value(configKey::clientId) == clientId) {
return renameClient(i, clientName, container, credentials);
}
}
beginResetModel();
QJsonObject client;
client[configKey::clientId] = clientId;
QJsonObject userData;
userData[configKey::clientName] = clientName;
client[configKey::userData] = userData;
m_clientsTable.push_back(client);
endResetModel();
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
ServerController serverController(m_settings);
const QString clientsTableFile =
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
}
return error;
}
ErrorCode ClientManagementModel::renameClient(const int row, const QString &clientName, const DockerContainer container,
ServerCredentials credentials)
{
auto client = m_clientsTable.at(row).toObject();
auto userData = client[configKey::userData].toObject();
userData[configKey::clientName] = clientName;
client[configKey::userData] = userData;
m_clientsTable.replace(row, client);
emit dataChanged(index(row, 0), index(row, 0));
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
ServerController serverController(m_settings);
const QString clientsTableFile =
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
ErrorCode error =
serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
}
return error;
}
ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContainer container,
ServerCredentials credentials)
{
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks
|| container == DockerContainer::Cloak) {
return revokeOpenVpn(row, container, credentials);
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
return revokeWireGuard(row, container, credentials);
}
return ErrorCode::NoError;
}
ErrorCode ClientManagementModel::revokeOpenVpn(const int row, const DockerContainer container,
ServerCredentials credentials)
{
auto client = m_clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString();
const QString getOpenVpnCertData = QString("sudo docker exec -i $CONTAINER_NAME bash -c '"
"cd /opt/amnezia/openvpn ;\\"
"easyrsa revoke %1 ;\\"
"easyrsa gen-crl ;\\"
"cp pki/crl.pem .'")
.arg(clientId);
ServerController serverController(m_settings);
const QString script =
serverController.replaceVars(getOpenVpnCertData, serverController.genVarsForScript(credentials, container));
ErrorCode error = serverController.runScript(credentials, script);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to revoke the certificate";
return error;
}
beginRemoveRows(QModelIndex(), row, row);
m_clientsTable.removeAt(row);
m_content.removeAt(row);
endRemoveRows();
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
const QString clientsTableFile =
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
return error;
}
return ErrorCode::NoError;
}
ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerContainer container,
ServerCredentials credentials)
{
ErrorCode error;
ServerController serverController(m_settings);
const QString wireGuardConfigFile =
QString("/opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg");
const QString wireguardConfigString =
serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, &error);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the wg conf file from the server";
return error;
}
auto client = m_clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString();
auto configSections = wireguardConfigString.split("[", Qt::SkipEmptyParts);
for (auto &section : configSections) {
if (section.contains(clientId)) {
configSections.removeOne(section);
break;
}
}
QString newWireGuardConfig = configSections.join("[");
newWireGuardConfig.insert(0, "[");
error = serverController.uploadTextFileToContainer(container, credentials, newWireGuardConfig, wireGuardConfigFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the wg conf file to the server";
return error;
}
beginRemoveRows(QModelIndex(), row, row);
m_clientsTable.removeAt(row);
endRemoveRows();
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
const QString clientsTableFile =
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
return error;
}
const QString script = "sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'";
error = serverController.runScript(
credentials,
serverController.replaceVars(script.arg(wireGuardConfigFile),
serverController.genVarsForScript(credentials, container)));
if (error != ErrorCode::NoError) {
logger.error() << "Failed to execute the command 'wg syncconf' on the server";
return error;
}
return ErrorCode::NoError;
return true;
}
QHash<int, QByteArray> ClientManagementModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[ClientNameRole] = "clientName";
roles[NameRole] = "clientName";
roles[OpenVpnCertIdRole] = "openvpnCertId";
roles[OpenVpnCertDataRole] = "openvpnCertData";
roles[WireGuardPublicKey] = "wireguardPublicKey";
return roles;
}

View File

@@ -2,48 +2,36 @@
#define CLIENTMANAGEMENTMODEL_H
#include <QAbstractListModel>
#include <QJsonArray>
#include "core/servercontroller.h"
#include "settings.h"
#include "protocols/protocols_defs.h"
class ClientManagementModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
ClientNameRole = Qt::UserRole + 1,
enum ClientRoles {
NameRole = Qt::UserRole + 1,
OpenVpnCertIdRole,
OpenVpnCertDataRole,
WireGuardPublicKey,
};
ClientManagementModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
ClientManagementModel(QObject *parent = nullptr);
void clearData();
void setContent(const QVector<QVariant> &data);
QJsonObject getContent(amnezia::Proto protocol);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
public slots:
ErrorCode updateModel(DockerContainer container, ServerCredentials credentials);
ErrorCode appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
ServerCredentials credentials);
ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container,
ServerCredentials credentials);
ErrorCode revokeClient(const int index, const DockerContainer container, ServerCredentials credentials);
void setData(const QModelIndex &index, QVariant data, int role = Qt::DisplayRole);
bool removeRows(int row);
protected:
QHash<int, QByteArray> roleNames() const override;
private:
bool isClientExists(const QString &clientId);
ErrorCode revokeOpenVpn(const int row, const DockerContainer container, ServerCredentials credentials);
ErrorCode revokeWireGuard(const int row, const DockerContainer container, ServerCredentials credentials);
ErrorCode getOpenVpnClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count);
ErrorCode getWireGuardClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count);
QJsonArray m_clientsTable;
std::shared_ptr<Settings> m_settings;
QVector<QVariant> m_content;
};
#endif // CLIENTMANAGEMENTMODEL_H

View File

@@ -22,6 +22,10 @@ bool ContainersModel::setData(const QModelIndex &index, const QVariant &value, i
DockerContainer container = ContainerProps::allContainers().at(index.row());
switch (role) {
case NameRole:
// return ContainerProps::containerHumanNames().value(container);
case DescriptionRole:
// return ContainerProps::containerDescriptions().value(container);
case ConfigRole: {
m_settings->setContainerConfig(m_currentlyProcessedServerIndex, container, value.toJsonObject());
m_containers = m_settings->containers(m_currentlyProcessedServerIndex);
@@ -31,15 +35,19 @@ bool ContainersModel::setData(const QModelIndex &index, const QVariant &value, i
break;
}
}
case IsDefaultRole: { //todo remove
case ServiceTypeRole:
// return ContainerProps::containerService(container);
case DockerContainerRole:
// return container;
case IsInstalledRole:
// return m_settings->containers(m_currentlyProcessedServerIndex).contains(container);
case IsDefaultRole: {
m_settings->setDefaultContainer(m_currentlyProcessedServerIndex, container);
m_defaultContainerIndex = container;
emit defaultContainerChanged();
}
default: break;
}
emit containersModelUpdated();
emit dataChanged(index, index);
return true;
}
@@ -109,14 +117,6 @@ QString ContainersModel::getDefaultContainerName()
return ContainerProps::containerHumanNames().value(m_defaultContainerIndex);
}
void ContainersModel::setDefaultContainer(int index)
{
auto container = static_cast<DockerContainer>(index);
m_settings->setDefaultContainer(m_currentlyProcessedServerIndex, container);
m_defaultContainerIndex = container;
emit defaultContainerChanged();
}
int ContainersModel::getCurrentlyProcessedContainerIndex()
{
return m_currentlyProcessedContainerIndex;
@@ -228,11 +228,6 @@ bool ContainersModel::isAnyContainerInstalled()
return false;
}
void ContainersModel::updateContainersConfig()
{
m_containers = m_settings->containers(m_currentlyProcessedServerIndex);
}
QHash<int, QByteArray> ContainersModel::roleNames() const
{
QHash<int, QByteArray> roles;

View File

@@ -46,7 +46,6 @@ public:
public slots:
DockerContainer getDefaultContainer();
QString getDefaultContainerName();
void setDefaultContainer(int index);
void setCurrentlyProcessedServerIndex(const int index);
@@ -66,14 +65,11 @@ public slots:
bool isAnyContainerInstalled();
void updateContainersConfig();
protected:
QHash<int, QByteArray> roleNames() const override;
signals:
void defaultContainerChanged();
void containersModelUpdated();
private:
QMap<DockerContainer, QJsonObject> m_containers;

View File

@@ -6,8 +6,7 @@ LanguageModel::LanguageModel(std::shared_ptr<Settings> settings, QObject *parent
QMetaEnum metaEnum = QMetaEnum::fromType<LanguageSettings::AvailableLanguageEnum>();
for (int i = 0; i < metaEnum.keyCount(); i++) {
m_availableLanguages.push_back(
LanguageModelData {getLocalLanguageName(static_cast<LanguageSettings::AvailableLanguageEnum>(i)),
static_cast<LanguageSettings::AvailableLanguageEnum>(i) });
LanguageModelData { metaEnum.valueToKey(i), static_cast<LanguageSettings::AvailableLanguageEnum>(i) });
}
}
@@ -37,26 +36,11 @@ QHash<int, QByteArray> LanguageModel::roleNames() const
return roles;
}
QString LanguageModel::getLocalLanguageName(const LanguageSettings::AvailableLanguageEnum language)
{
QString strLanguage("");
switch (language) {
case LanguageSettings::AvailableLanguageEnum::English: strLanguage = "English"; break;
case LanguageSettings::AvailableLanguageEnum::Russian: strLanguage = "Русский"; break;
case LanguageSettings::AvailableLanguageEnum::China_cn: strLanguage = "\347\256\200\344\275\223\344\270\255\346\226\207"; break;
default:
break;
}
return strLanguage;
}
void LanguageModel::changeLanguage(const LanguageSettings::AvailableLanguageEnum language)
{
switch (language) {
case LanguageSettings::AvailableLanguageEnum::English: emit updateTranslations(QLocale::English); break;
case LanguageSettings::AvailableLanguageEnum::Russian: emit updateTranslations(QLocale::Russian); break;
case LanguageSettings::AvailableLanguageEnum::China_cn: emit updateTranslations(QLocale::Chinese); break;
default: emit updateTranslations(QLocale::English); break;
}
}
@@ -67,7 +51,6 @@ int LanguageModel::getCurrentLanguageIndex()
switch (locale.language()) {
case QLocale::English: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
case QLocale::Russian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Russian); break;
case QLocale::Chinese: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::China_cn); break;
default: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
}
}

View File

@@ -11,8 +11,7 @@ namespace LanguageSettings
Q_NAMESPACE
enum class AvailableLanguageEnum {
English,
Russian,
China_cn
Russian
};
Q_ENUM_NS(AvailableLanguageEnum)
@@ -60,8 +59,6 @@ protected:
QHash<int, QByteArray> roleNames() const override;
private:
QString getLocalLanguageName(const LanguageSettings::AvailableLanguageEnum language);
QVector<LanguageModelData> m_availableLanguages;
std::shared_ptr<Settings> m_settings;

View File

@@ -1,137 +0,0 @@
#include "awgConfigModel.h"
#include <QJsonDocument>
#include "protocols/protocols_defs.h"
AwgConfigModel::AwgConfigModel(QObject *parent) : QAbstractListModel(parent)
{
}
int AwgConfigModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 1;
}
bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || index.row() < 0 || index.row() >= ContainerProps::allContainers().size()) {
return false;
}
switch (role) {
case Roles::PortRole: m_protocolConfig.insert(config_key::port, value.toString()); break;
case Roles::JunkPacketCountRole: m_protocolConfig.insert(config_key::junkPacketCount, value.toString()); break;
case Roles::JunkPacketMinSizeRole: m_protocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break;
case Roles::JunkPacketMaxSizeRole: m_protocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break;
case Roles::InitPacketJunkSizeRole:
m_protocolConfig.insert(config_key::initPacketJunkSize, value.toString());
break;
case Roles::ResponsePacketJunkSizeRole:
m_protocolConfig.insert(config_key::responsePacketJunkSize, value.toString());
break;
case Roles::InitPacketMagicHeaderRole:
m_protocolConfig.insert(config_key::initPacketMagicHeader, value.toString());
break;
case Roles::ResponsePacketMagicHeaderRole:
m_protocolConfig.insert(config_key::responsePacketMagicHeader, value.toString());
break;
case Roles::UnderloadPacketMagicHeaderRole:
m_protocolConfig.insert(config_key::underloadPacketMagicHeader, value.toString());
break;
case Roles::TransportPacketMagicHeaderRole:
m_protocolConfig.insert(config_key::transportPacketMagicHeader, value.toString());
break;
}
emit dataChanged(index, index, QList { role });
return true;
}
QVariant AwgConfigModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= rowCount()) {
return false;
}
switch (role) {
case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString();
case Roles::JunkPacketCountRole: return m_protocolConfig.value(config_key::junkPacketCount);
case Roles::JunkPacketMinSizeRole: return m_protocolConfig.value(config_key::junkPacketMinSize);
case Roles::JunkPacketMaxSizeRole: return m_protocolConfig.value(config_key::junkPacketMaxSize);
case Roles::InitPacketJunkSizeRole: return m_protocolConfig.value(config_key::initPacketJunkSize);
case Roles::ResponsePacketJunkSizeRole: return m_protocolConfig.value(config_key::responsePacketJunkSize);
case Roles::InitPacketMagicHeaderRole: return m_protocolConfig.value(config_key::initPacketMagicHeader);
case Roles::ResponsePacketMagicHeaderRole: return m_protocolConfig.value(config_key::responsePacketMagicHeader);
case Roles::UnderloadPacketMagicHeaderRole: return m_protocolConfig.value(config_key::underloadPacketMagicHeader);
case Roles::TransportPacketMagicHeaderRole: return m_protocolConfig.value(config_key::transportPacketMagicHeader);
}
return QVariant();
}
void AwgConfigModel::updateModel(const QJsonObject &config)
{
beginResetModel();
m_container = ContainerProps::containerFromString(config.value(config_key::container).toString());
m_fullConfig = config;
QJsonObject protocolConfig = config.value(config_key::awg).toObject();
m_protocolConfig[config_key::port] =
protocolConfig.value(config_key::port).toString(protocols::awg::defaultPort);
m_protocolConfig[config_key::junkPacketCount] =
protocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
m_protocolConfig[config_key::junkPacketMinSize] =
protocolConfig.value(config_key::junkPacketMinSize)
.toString(protocols::awg::defaultJunkPacketMinSize);
m_protocolConfig[config_key::junkPacketMaxSize] =
protocolConfig.value(config_key::junkPacketMaxSize)
.toString(protocols::awg::defaultJunkPacketMaxSize);
m_protocolConfig[config_key::initPacketJunkSize] =
protocolConfig.value(config_key::initPacketJunkSize)
.toString(protocols::awg::defaultInitPacketJunkSize);
m_protocolConfig[config_key::responsePacketJunkSize] =
protocolConfig.value(config_key::responsePacketJunkSize)
.toString(protocols::awg::defaultResponsePacketJunkSize);
m_protocolConfig[config_key::initPacketMagicHeader] =
protocolConfig.value(config_key::initPacketMagicHeader)
.toString(protocols::awg::defaultInitPacketMagicHeader);
m_protocolConfig[config_key::responsePacketMagicHeader] =
protocolConfig.value(config_key::responsePacketMagicHeader)
.toString(protocols::awg::defaultResponsePacketMagicHeader);
m_protocolConfig[config_key::underloadPacketMagicHeader] =
protocolConfig.value(config_key::underloadPacketMagicHeader)
.toString(protocols::awg::defaultUnderloadPacketMagicHeader);
m_protocolConfig[config_key::transportPacketMagicHeader] =
protocolConfig.value(config_key::transportPacketMagicHeader)
.toString(protocols::awg::defaultTransportPacketMagicHeader);
endResetModel();
}
QJsonObject AwgConfigModel::getConfig()
{
m_fullConfig.insert(config_key::awg, m_protocolConfig);
return m_fullConfig;
}
QHash<int, QByteArray> AwgConfigModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[PortRole] = "port";
roles[JunkPacketCountRole] = "junkPacketCount";
roles[JunkPacketMinSizeRole] = "junkPacketMinSize";
roles[JunkPacketMaxSizeRole] = "junkPacketMaxSize";
roles[InitPacketJunkSizeRole] = "initPacketJunkSize";
roles[ResponsePacketJunkSizeRole] = "responsePacketJunkSize";
roles[InitPacketMagicHeaderRole] = "initPacketMagicHeader";
roles[ResponsePacketMagicHeaderRole] = "responsePacketMagicHeader";
roles[UnderloadPacketMagicHeaderRole] = "underloadPacketMagicHeader";
roles[TransportPacketMagicHeaderRole] = "transportPacketMagicHeader";
return roles;
}

View File

@@ -1,47 +0,0 @@
#ifndef AWGCONFIGMODEL_H
#define AWGCONFIGMODEL_H
#include <QAbstractListModel>
#include <QJsonObject>
#include "containers/containers_defs.h"
class AwgConfigModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
PortRole = Qt::UserRole + 1,
JunkPacketCountRole,
JunkPacketMinSizeRole,
JunkPacketMaxSizeRole,
InitPacketJunkSizeRole,
ResponsePacketJunkSizeRole,
InitPacketMagicHeaderRole,
ResponsePacketMagicHeaderRole,
UnderloadPacketMagicHeaderRole,
TransportPacketMagicHeaderRole
};
explicit AwgConfigModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
public slots:
void updateModel(const QJsonObject &config);
QJsonObject getConfig();
protected:
QHash<int, QByteArray> roleNames() const override;
private:
DockerContainer m_container;
QJsonObject m_protocolConfig;
QJsonObject m_fullConfig;
};
#endif // AWGCONFIGMODEL_H

View File

@@ -78,11 +78,12 @@ PageLoader::PageEnum ProtocolsModel::protocolPage(Proto protocol) const
case Proto::ShadowSocks: return PageLoader::PageEnum::PageProtocolShadowSocksSettings;
case Proto::WireGuard: return PageLoader::PageEnum::PageProtocolWireGuardSettings;
case Proto::Ikev2: return PageLoader::PageEnum::PageProtocolIKev2Settings;
case Proto::L2tp: return PageLoader::PageEnum::PageProtocolIKev2Settings;
case Proto::L2tp: return PageLoader::PageEnum::PageProtocolOpenVpnSettings;
// non-vpn
case Proto::TorWebSite: return PageLoader::PageEnum::PageServiceTorWebsiteSettings;
case Proto::Dns: return PageLoader::PageEnum::PageServiceDnsSettings;
case Proto::Sftp: return PageLoader::PageEnum::PageServiceSftpSettings;
case Proto::TorWebSite: return PageLoader::PageEnum::PageProtocolOpenVpnSettings;
case Proto::Dns: return PageLoader::PageEnum::PageProtocolOpenVpnSettings;
case Proto::FileShare: return PageLoader::PageEnum::PageProtocolOpenVpnSettings;
case Proto::Sftp: return PageLoader::PageEnum::PageProtocolOpenVpnSettings;
default: return PageLoader::PageEnum::PageProtocolOpenVpnSettings;
}
}

View File

@@ -96,7 +96,7 @@ void ServersModel::setDefaultServerIndex(const int index)
{
m_settings->setDefaultServer(index);
m_defaultServerIndex = m_settings->defaultServerIndex();
emit defaultServerIndexChanged(m_defaultServerIndex);
emit defaultServerIndexChanged();
}
const int ServersModel::getDefaultServerIndex()
@@ -145,11 +145,6 @@ QString ServersModel::getCurrentlyProcessedServerHostName()
return qvariant_cast<QString>(data(m_currentlyProcessedServerIndex, HostNameRole));
}
const ServerCredentials ServersModel::getCurrentlyProcessedServerCredentials()
{
return serverCredentials(m_currentlyProcessedServerIndex);
}
bool ServersModel::isDefaultServerCurrentlyProcessed()
{
return m_defaultServerIndex == m_currentlyProcessedServerIndex;
@@ -198,12 +193,6 @@ bool ServersModel::isDefaultServerConfigContainsAmneziaDns()
return primaryDns == protocols::dns::amneziaDnsIp;
}
void ServersModel::updateContainersConfig()
{
auto server = m_settings->server(m_currentlyProcessedServerIndex);
m_servers.replace(m_currentlyProcessedServerIndex, server);
}
QHash<int, QByteArray> ServersModel::roleNames() const
{
QHash<int, QByteArray> roles;

View File

@@ -53,21 +53,18 @@ public slots:
int getCurrentlyProcessedServerIndex();
QString getCurrentlyProcessedServerHostName();
const ServerCredentials getCurrentlyProcessedServerCredentials();
void addServer(const QJsonObject &server);
void removeServer();
bool isDefaultServerConfigContainsAmneziaDns();
void updateContainersConfig();
protected:
QHash<int, QByteArray> roleNames() const override;
signals:
void currentlyProcessedServerIndexChanged(const int index);
void defaultServerIndexChanged(const int index);
void defaultServerIndexChanged();
void defaultServerNameChanged();
private:

View File

@@ -3,14 +3,7 @@
SitesModel::SitesModel(std::shared_ptr<Settings> settings, QObject *parent)
: QAbstractListModel(parent), m_settings(settings)
{
auto routeMode = m_settings->routeMode();
if (routeMode == Settings::RouteMode::VpnAllSites) {
m_isSplitTunnelingEnabled = false;
m_currentRouteMode = Settings::RouteMode::VpnOnlyForwardSites;
} else {
m_isSplitTunnelingEnabled = true;
m_currentRouteMode = routeMode;
}
m_currentRouteMode = m_settings->routeMode();
fillSites();
}
@@ -100,21 +93,6 @@ void SitesModel::setRouteMode(int routeMode)
emit routeModeChanged();
}
bool SitesModel::isSplitTunnelingEnabled()
{
return m_isSplitTunnelingEnabled;
}
void SitesModel::toggleSplitTunneling(bool enabled)
{
if (enabled) {
setRouteMode(m_currentRouteMode);
} else {
m_settings->setRouteMode(Settings::RouteMode::VpnAllSites);
}
m_isSplitTunnelingEnabled = enabled;
}
QVector<QPair<QString, QString> > SitesModel::getCurrentSites()
{
return m_sites;

View File

@@ -31,9 +31,6 @@ public slots:
int getRouteMode();
void setRouteMode(int routeMode);
bool isSplitTunnelingEnabled();
void toggleSplitTunneling(bool enabled);
QVector<QPair<QString, QString>> getCurrentSites();
signals:
@@ -47,7 +44,6 @@ private:
std::shared_ptr<Settings> m_settings;
bool m_isSplitTunnelingEnabled;
Settings::RouteMode m_currentRouteMode;
QVector<QPair<QString, QString>> m_sites;

Some files were not shown because too many files have changed in this diff Show More