OpenVPN3 pluggable transport cloak for ios (#227)

OpenVPN3 pluggable transport cloak for ios
This commit is contained in:
pokamest
2023-05-23 11:14:28 -07:00
committed by GitHub
parent 4ddddec978
commit 330c341922
18 changed files with 206 additions and 1171 deletions

5
.gitmodules vendored
View File

@@ -6,7 +6,7 @@
url = https://github.com/WireGuard/wireguard-apple
[submodule "client/3rd/OpenVPNAdapter"]
path = client/3rd/OpenVPNAdapter
url = https://github.com/ss-abramchuk/OpenVPNAdapter.git
url = https://github.com/amnezia-vpn/OpenVPNAdapter.git
[submodule "client/3rd/ShadowPath"]
path = client/3rd/ShadowPath
url = https://github.com/qman9501/ShadowPath
@@ -28,9 +28,6 @@
[submodule "client/3rd/zlib"]
path = client/3rd/zlib
url = https://github.com/madler/zlib.git
[submodule "deploy/amnezia-ios-certificates"]
path = deploy/amnezia-ios-certificates
url = https://github.com/amnezia-vpn/amnezia-ios-certificates.git
[submodule "client/3rd/SortFilterProxyModel"]
path = client/3rd/SortFilterProxyModel
url = https://github.com/mitchcurtis/SortFilterProxyModel.git

View File

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

View File

@@ -48,7 +48,8 @@ endif()
qt_standard_project_setup()
if(IOS)
execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/scripts/openvpn.sh args
#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()
@@ -313,7 +314,6 @@ if(IOS)
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/protocols/ios_vpnprotocol.h
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/iosnotificationhandler.h
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/json.h
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/bigint.h
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/bigintipv6addr.h
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/ipaddress.h
@@ -325,7 +325,6 @@ if(IOS)
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/protocols/ios_vpnprotocol.mm
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/iosnotificationhandler.mm
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/json.cpp
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/iosglue.mm
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/ipaddress.cpp
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/ipaddressrange.cpp
@@ -362,7 +361,7 @@ if(IOS)
target_include_directories(${PROJECT} PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
set(BUILD_ID ${A_PROJECT_BUILD})
set(APPLE_PROJECT_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
set_target_properties(${PROJECT} PROPERTIES
XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION
@@ -373,12 +372,12 @@ if(IOS)
MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPN"
MACOSX_BUNDLE_GUI_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}"
MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
MACOSX_BUNDLE_LONG_VERSION_STRING "${CMAKE_PROJECT_VERSION}-${BUILD_ID}"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${CMAKE_PROJECT_VERSION}"
MACOSX_BUNDLE_LONG_VERSION_STRING "${APPLE_PROJECT_VERSION}-${CMAKE_PROJECT_VERSION_TWEAK}"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${APPLE_PROJECT_VERSION}"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_LIST_DIR}/ios/app/main.entitlements"
XCODE_ATTRIBUTE_MARKETING_VERSION "${APP_MAJOR_VERSION}"
XCODE_ATTRIBUTE_MARKETING_VERSION "${APPLE_PROJECT_VERSION}"
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPN"
XCODE_ATTRIBUTE_BUNDLE_INFO_STRING "AmneziaVPN"

View File

@@ -39,7 +39,7 @@ QString CloakConfigurator::genCloakConfig(const ServerCredentials &credentials,
config.insert("UID", cloakBypassUid);
config.insert("PublicKey", cloakPublicKey);
config.insert("ServerName", "$FAKE_WEB_SITE_ADDRESS");
config.insert("NumConn", 4);
config.insert("NumConn", 1);
config.insert("BrowserSig", "chrome");
config.insert("StreamTimeout", 300);

View File

@@ -155,6 +155,7 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
switch (c) {
case DockerContainer::WireGuard: return true;
case DockerContainer::OpenVpn: return true;
case DockerContainer::Cloak: return true;
// case DockerContainer::ShadowSocks: return true;
default: return false;
}

View File

@@ -12,6 +12,8 @@ set_target_properties(networkextension PROPERTIES
MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPNNetworkExtension"
MACOSX_BUNDLE_GUI_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}.network-extension"
MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
MACOSX_BUNDLE_LONG_VERSION_STRING "${APPLE_PROJECT_VERSION}-${CMAKE_PROJECT_VERSION_TWEAK}"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${APPLE_PROJECT_VERSION}"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}.network-extension"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CMAKE_CURRENT_SOURCE_DIR}/AmneziaVPNNetworkExtension.entitlements

14
client/ios/scripts/clangwrap.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/sh
# go/clangwrap.sh
SDK_PATH=`xcrun --sdk $SDK --show-sdk-path`
CLANG=`xcrun --sdk $SDK --find clang`
if [ "$GOARCH" == "amd64" ]; then
CARCH="x86_64"
elif [ "$GOARCH" == "arm64" ]; then
CARCH="arm64"
fi
exec $CLANG -arch $CARCH -isysroot $SDK_PATH -mios-version-min=10.0 "$@"

View File

@@ -1,13 +1,12 @@
XCODEBUILD="/usr/bin/xcodebuild"
WORKINGDIR=`pwd`
PATCH="/usr/bin/patch"
cat $WORKINGDIR/3rd/OpenVPNAdapter/Configuration/Project.xcconfig > $WORKINGDIR/3rd/OpenVPNAdapter/Configuration/amnezia.xcconfig
cat << EOF >> $WORKINGDIR/3rd/OpenVPNAdapter/Configuration/amnezia.xcconfig
cat $WORKINGDIR/3rd/OpenVPNAdapter/Configuration/Project.xcconfig > $WORKINGDIR/3rd/OpenVPNAdapter/Configuration/amnezia.xcconfig
cat << EOF >> $WORKINGDIR/3rd/OpenVPNAdapter/Configuration/amnezia.xcconfig
PROJECT_TEMP_DIR = $WORKINGDIR/3rd/OpenVPNAdapter/build/OpenVPNAdapter.build
CONFIGURATION_BUILD_DIR = $WORKINGDIR/3rd/OpenVPNAdapter/build/Release-iphoneos
BUILT_PRODUCTS_DIR = $WORKINGDIR/3rd/OpenVPNAdapter/build/Release-iphoneos
BUILT_PRODUCTS_DIR = $WORKINGDIR/3rd/OpenVPNAdapter/build/Release-iphoneos
EOF
@@ -18,4 +17,3 @@ EOF
echo "OpenVPNAdapter build failed"
fi
cd ../../

View File

@@ -236,7 +236,6 @@ public class IOSControllerImpl : NSObject {
}
@objc func checkStatus(callback: @escaping (String, String, String) -> Void) {
Logger.global?.log(message: "Check status")
assert(tunnel != nil)
let proto = tunnel!.protocolConfiguration as? NETunnelProviderProtocol

View File

@@ -48,7 +48,7 @@ func wg_log(_ type: OSLogType, staticMessage msg: StaticString) {
}
func wg_log(_ type: OSLogType, message msg: String) {
os_log("%{public}s", log: OSLog.default, type: type, msg)
os_log("%{AMNEZIA}s", log: OSLog.default, type: type, msg)
Logger.global?.log(message: msg)
NSLog("AMNEZIA: \(msg)")
}

View File

@@ -688,23 +688,18 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
}
*/
private func setupAndlaunchOpenVPN(withConfig ovpnConfiguration: Data, withShadowSocks viaSS: Bool = false, completionHandler: @escaping (Error?) -> Void) {
wg_log(.info, message: "Inside setupAndlaunchOpenVPN()")
let str = String(decoding: ovpnConfiguration, as: UTF8.self)
wg_log(.info, message: "OPENVPN config: \(str)")
let configuration = OpenVPNConfiguration()
configuration.fileContent = ovpnConfiguration
if viaSS {
// configuration.settings = [
// "remote": "137.74.6.148 1194",
// "proto": "tcp",
// "link-mtu": "1480",
// "tun-mtu": "1460",
// ]
if(str.contains("cloak")){
configuration.setPTCloak();
}
let evaluation: OpenVPNConfigurationEvaluation
do {
evaluation = try ovpnAdapter.apply(configuration: configuration)
} catch {
completionHandler(error)
return

View File

@@ -41,8 +41,6 @@ public class IOSVpnProtocolImpl : NSObject {
super.init()
Logger.configureGlobal(tagged: "APP", withFilePath: "")
print("Config from caller: \(config)")
vpnBundleID = bundleID;
precondition(!vpnBundleID.isEmpty)
@@ -296,7 +294,7 @@ public class IOSVpnProtocolImpl : NSObject {
@objc func connect(ssConfig: String,
ovpnConfig: String,
failureCallback: @escaping () -> Void) {
Logger.global?.log(message: "Connecting")
Logger.global?.log(message: "Logger Connecting")
// assert(tunnel != nil)
self.openVPNConfig = ovpnConfig
@@ -315,7 +313,7 @@ public class IOSVpnProtocolImpl : NSObject {
}
@objc func connect(ovpnConfig: String, failureCallback: @escaping () -> Void) {
Logger.global?.log(message: "Connecting")
Logger.global?.log(message: "Logger Connecting")
// assert(tunnel != nil)
let addr: String = ovpnConfig
@@ -331,7 +329,7 @@ public class IOSVpnProtocolImpl : NSObject {
}
@objc func connect(dnsServer: String, serverIpv6Gateway: String, serverPublicKey: String, presharedKey: String, serverIpv4AddrIn: String, serverPort: Int, allowedIPAddressRanges: Array<VPNIPAddressRange>, ipv6Enabled: Bool, reason: Int, failureCallback: @escaping () -> Void) {
Logger.global?.log(message: "Connecting")
Logger.global?.log(message: "Logger Connecting")
// assert(tunnel != nil)
// Let's remove the previous config if it exists.
@@ -525,11 +523,7 @@ public class IOSVpnProtocolImpl : NSObject {
}
@objc func checkStatus(callback: @escaping (String, String, String) -> Void) {
Logger.global?.log(message: "Check status")
// assert(tunnel != nil)
print("check status")
let protoType = (tunnel!.localizedDescription ?? "").toTunnelType
print(protoType);
switch protoType {
case .wireguard:
@@ -545,7 +539,6 @@ public class IOSVpnProtocolImpl : NSObject {
}
private func checkShadowSocksStatus(callback: @escaping (String, String, String) -> Void) {
Logger.global?.log(message: "Check ShadowSocks")
guard let proto = tunnel?.protocolConfiguration as? NETunnelProviderProtocol else {
callback("", "", "")
return
@@ -557,11 +550,8 @@ public class IOSVpnProtocolImpl : NSObject {
callback("", "", "")
return
}
print("server IP: \(serverIpv4Gateway)")
let deviceIpv4Address = getWiFiAddress()
print("device IP: \(serverIpv4Gateway)")
if deviceIpv4Address == nil {
callback("", "", "")
return
@@ -591,7 +581,6 @@ public class IOSVpnProtocolImpl : NSObject {
}
private func checkOVPNStatus(callback: @escaping (String, String, String) -> Void) {
Logger.global?.log(message: "Check OpenVPN")
guard let proto = tunnel?.protocolConfiguration as? NETunnelProviderProtocol else {
callback("", "", "")
return
@@ -607,13 +596,8 @@ public class IOSVpnProtocolImpl : NSObject {
.splitToArray(separator: "\n", trimmingCharacters: nil)
.first { $0.starts(with: "remote ") }
.splitToArray(separator: " ", trimmingCharacters: nil)[1]
print("server IP: \(serverIpv4Gateway)")
let deviceIpv4Address = getWiFiAddress()
print("device IP: \(deviceIpv4Address)")
if deviceIpv4Address == nil {
callback("", "", "")
return

View File

@@ -1,732 +0,0 @@
/**
* QtJson - A simple class for parsing JSON data into a QVariant hierarchies and vice-versa.
* Copyright (C) 2011 Eeli Reilin
*
* 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 3 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* \file json.cpp
*/
#include <QDateTime>
#include <QStringList>
#include "json.h"
namespace QtJson {
static QString dateFormat, dateTimeFormat;
static bool prettySerialize = false;
static QString sanitizeString(QString str);
static QByteArray join(const QList<QByteArray> &list, const QByteArray &sep);
static QVariant parseValue(const QString &json, int &index, bool &success);
static QVariant parseObject(const QString &json, int &index, bool &success);
static QVariant parseArray(const QString &json, int &index, bool &success);
static QVariant parseString(const QString &json, int &index, bool &success);
static QVariant parseNumber(const QString &json, int &index);
static int lastIndexOfNumber(const QString &json, int index);
static void eatWhitespace(const QString &json, int &index);
static int lookAhead(const QString &json, int index);
static int nextToken(const QString &json, int &index);
template<typename T>
QByteArray serializeMap(const T &map, bool &success, int _level = 0) {
QByteArray newline;
QByteArray tabs;
QByteArray tabsFields;
if (prettySerialize && !map.isEmpty()) {
newline = "\n";
for (uint l=1; l<_level; l++) {
tabs += " ";
}
tabsFields = tabs + " ";
}
QByteArray str = "{" + newline;
QList<QByteArray> pairs;
for (typename T::const_iterator it = map.begin(), itend = map.end(); it != itend; ++it) {
bool otherSuccess = true;
QByteArray serializedValue = serialize(it.value(), otherSuccess, _level);
if (serializedValue.isNull()) {
success = false;
break;
}
pairs << tabsFields + sanitizeString(it.key()).toUtf8() + ":" + (prettySerialize ? " " : "") + serializedValue;
}
str += join(pairs, "," + newline) + newline;
str += tabs + "}";
return str;
}
void insert(QVariant &v, const QString &key, const QVariant &value);
void append(QVariant &v, const QVariant &value);
template<typename T>
void cloneMap(QVariant &json, const T &map) {
for (typename T::const_iterator it = map.begin(), itend = map.end(); it != itend; ++it) {
insert(json, it.key(), (*it));
}
}
template<typename T>
void cloneList(QVariant &json, const T &list) {
for (typename T::const_iterator it = list.begin(), itend = list.end(); it != itend; ++it) {
append(json, (*it));
}
}
/**
* parse
*/
QVariant parse(const QString &json) {
bool success = true;
return parse(json, success);
}
/**
* parse
*/
QVariant parse(const QString &json, bool &success) {
success = true;
// Return an empty QVariant if the JSON data is either null or empty
if (!json.isNull() || !json.isEmpty()) {
QString data = json;
// We'll start from index 0
int index = 0;
// Parse the first value
QVariant value = parseValue(data, index, success);
// Return the parsed value
return value;
} else {
// Return the empty QVariant
return QVariant();
}
}
/**
* clone
*/
QVariant clone(const QVariant &data) {
QVariant v;
if (data.type() == QVariant::Map) {
cloneMap(v, data.toMap());
} else if (data.type() == QVariant::Hash) {
cloneMap(v, data.toHash());
} else if (data.type() == QVariant::List) {
cloneList(v, data.toList());
} else if (data.type() == QVariant::StringList) {
cloneList(v, data.toStringList());
} else {
v = QVariant(data);
}
return v;
}
/**
* insert value (map case)
*/
void insert(QVariant &v, const QString &key, const QVariant &value) {
if (!v.canConvert<QVariantMap>()) v = QVariantMap();
QVariantMap *p = (QVariantMap *)v.data();
p->insert(key, clone(value));
}
/**
* append value (list case)
*/
void append(QVariant &v, const QVariant &value) {
if (!v.canConvert<QVariantList>()) v = QVariantList();
QVariantList *p = (QVariantList *)v.data();
p->append(value);
}
QByteArray serialize(const QVariant &data) {
bool success = true;
return serialize(data, success);
}
QByteArray serialize(const QVariant &data, bool &success, int _level /*= 0*/) {
QByteArray newline;
QByteArray tabs;
QByteArray tabsFields;
if (prettySerialize) {
newline = "\n";
for (uint l=0; l<_level; l++) {
tabs += " ";
}
tabsFields = tabs + " ";
}
QByteArray str;
success = true;
if (!data.isValid()) { // invalid or null?
str = "null";
} else if ((data.type() == QVariant::List) ||
(data.type() == QVariant::StringList)) { // variant is a list?
QList<QByteArray> values;
const QVariantList list = data.toList();
Q_FOREACH(const QVariant& v, list) {
bool otherSuccess = true;
QByteArray serializedValue = serialize(v, otherSuccess, _level+1);
if (serializedValue.isNull()) {
success = false;
break;
}
values << tabsFields + serializedValue;
}
if (!values.isEmpty()) {
str = "[" + newline + join( values, "," + newline ) + newline + tabs + "]";
} else {
str = "[]";
}
} else if (data.type() == QVariant::Hash) { // variant is a hash?
str = serializeMap<>(data.toHash(), success, _level+1);
} else if (data.type() == QVariant::Map) { // variant is a map?
str = serializeMap<>(data.toMap(), success, _level+1);
} else if ((data.type() == QVariant::String) ||
(data.type() == QVariant::ByteArray)) {// a string or a byte array?
str = sanitizeString(data.toString()).toUtf8();
} else if (data.type() == QVariant::Double) { // double?
double value = data.toDouble(&success);
if (success) {
str = QByteArray::number(value, 'g');
if (!str.contains(".") && ! str.contains("e")) {
str += ".0";
}
}
} else if (data.type() == QVariant::Bool) { // boolean value?
str = data.toBool() ? "true" : "false";
} else if (data.type() == QVariant::ULongLong) { // large unsigned number?
str = QByteArray::number(data.value<qulonglong>());
} else if (data.canConvert<qlonglong>()) { // any signed number?
str = QByteArray::number(data.value<qlonglong>());
} else if (data.canConvert<long>()) { //TODO: this code is never executed because all smaller types can be converted to qlonglong
str = QString::number(data.value<long>()).toUtf8();
} else if (data.type() == QVariant::DateTime) { // datetime value?
str = sanitizeString(dateTimeFormat.isEmpty()
? data.toDateTime().toString()
: data.toDateTime().toString(dateTimeFormat)).toUtf8();
} else if (data.type() == QVariant::Date) { // date value?
str = sanitizeString(dateTimeFormat.isEmpty()
? data.toDate().toString()
: data.toDate().toString(dateFormat)).toUtf8();
} else if (data.canConvert<QString>()) { // can value be converted to string?
// this will catch QUrl, ... (all other types which can be converted to string)
str = sanitizeString(data.toString()).toUtf8();
} else {
success = false;
}
if (success) {
return str;
}
return QByteArray();
}
QString serializeStr(const QVariant &data) {
return QString::fromUtf8(serialize(data));
}
QString serializeStr(const QVariant &data, bool &success) {
return QString::fromUtf8(serialize(data, success));
}
/**
* \enum JsonToken
*/
enum JsonToken {
JsonTokenNone = 0,
JsonTokenCurlyOpen = 1,
JsonTokenCurlyClose = 2,
JsonTokenSquaredOpen = 3,
JsonTokenSquaredClose = 4,
JsonTokenColon = 5,
JsonTokenComma = 6,
JsonTokenString = 7,
JsonTokenNumber = 8,
JsonTokenTrue = 9,
JsonTokenFalse = 10,
JsonTokenNull = 11
};
static QString sanitizeString(QString str) {
str.replace(QLatin1String("\\"), QLatin1String("\\\\"));
str.replace(QLatin1String("\""), QLatin1String("\\\""));
str.replace(QLatin1String("\b"), QLatin1String("\\b"));
str.replace(QLatin1String("\f"), QLatin1String("\\f"));
str.replace(QLatin1String("\n"), QLatin1String("\\n"));
str.replace(QLatin1String("\r"), QLatin1String("\\r"));
str.replace(QLatin1String("\t"), QLatin1String("\\t"));
return QString(QLatin1String("\"%1\"")).arg(str);
}
static QByteArray join(const QList<QByteArray> &list, const QByteArray &sep) {
QByteArray res;
Q_FOREACH(const QByteArray &i, list) {
if (!res.isEmpty()) {
res += sep;
}
res += i;
}
return res;
}
/**
* parseValue
*/
static QVariant parseValue(const QString &json, int &index, bool &success) {
// Determine what kind of data we should parse by
// checking out the upcoming token
switch(lookAhead(json, index)) {
case JsonTokenString:
return parseString(json, index, success);
case JsonTokenNumber:
return parseNumber(json, index);
case JsonTokenCurlyOpen:
return parseObject(json, index, success);
case JsonTokenSquaredOpen:
return parseArray(json, index, success);
case JsonTokenTrue:
nextToken(json, index);
return QVariant(true);
case JsonTokenFalse:
nextToken(json, index);
return QVariant(false);
case JsonTokenNull:
nextToken(json, index);
return QVariant();
case JsonTokenNone:
break;
}
// If there were no tokens, flag the failure and return an empty QVariant
success = false;
return QVariant();
}
/**
* parseObject
*/
static QVariant parseObject(const QString &json, int &index, bool &success) {
QVariantMap map;
int token;
// Get rid of the whitespace and increment index
nextToken(json, index);
// Loop through all of the key/value pairs of the object
bool done = false;
while (!done) {
// Get the upcoming token
token = lookAhead(json, index);
if (token == JsonTokenNone) {
success = false;
return QVariantMap();
} else if (token == JsonTokenComma) {
nextToken(json, index);
} else if (token == JsonTokenCurlyClose) {
nextToken(json, index);
return map;
} else {
// Parse the key/value pair's name
QString name = parseString(json, index, success).toString();
if (!success) {
return QVariantMap();
}
// Get the next token
token = nextToken(json, index);
// If the next token is not a colon, flag the failure
// return an empty QVariant
if (token != JsonTokenColon) {
success = false;
return QVariant(QVariantMap());
}
// Parse the key/value pair's value
QVariant value = parseValue(json, index, success);
if (!success) {
return QVariantMap();
}
// Assign the value to the key in the map
map[name] = value;
}
}
// Return the map successfully
return QVariant(map);
}
/**
* parseArray
*/
static QVariant parseArray(const QString &json, int &index, bool &success) {
QVariantList list;
nextToken(json, index);
bool done = false;
while(!done) {
int token = lookAhead(json, index);
if (token == JsonTokenNone) {
success = false;
return QVariantList();
} else if (token == JsonTokenComma) {
nextToken(json, index);
} else if (token == JsonTokenSquaredClose) {
nextToken(json, index);
break;
} else {
QVariant value = parseValue(json, index, success);
if (!success) {
return QVariantList();
}
list.push_back(value);
}
}
return QVariant(list);
}
/**
* parseString
*/
static QVariant parseString(const QString &json, int &index, bool &success) {
QString s;
QChar c;
eatWhitespace(json, index);
c = json[index++];
bool complete = false;
while(!complete) {
if (index == json.size()) {
break;
}
c = json[index++];
if (c == '\"') {
complete = true;
break;
} else if (c == '\\') {
if (index == json.size()) {
break;
}
c = json[index++];
if (c == '\"') {
s.append('\"');
} else if (c == '\\') {
s.append('\\');
} else if (c == '/') {
s.append('/');
} else if (c == 'b') {
s.append('\b');
} else if (c == 'f') {
s.append('\f');
} else if (c == 'n') {
s.append('\n');
} else if (c == 'r') {
s.append('\r');
} else if (c == 't') {
s.append('\t');
} else if (c == 'u') {
int remainingLength = json.size() - index;
if (remainingLength >= 4) {
QString unicodeStr = json.mid(index, 4);
int symbol = unicodeStr.toInt(0, 16);
s.append(QChar(symbol));
index += 4;
} else {
break;
}
}
} else {
s.append(c);
}
}
if (!complete) {
success = false;
return QVariant();
}
return QVariant(s);
}
/**
* parseNumber
*/
static QVariant parseNumber(const QString &json, int &index) {
eatWhitespace(json, index);
int lastIndex = lastIndexOfNumber(json, index);
int charLength = (lastIndex - index) + 1;
QString numberStr;
numberStr = json.mid(index, charLength);
index = lastIndex + 1;
bool ok;
if (numberStr.contains('.')) {
return QVariant(numberStr.toDouble(NULL));
} else if (numberStr.startsWith('-')) {
int i = numberStr.toInt(&ok);
if (!ok) {
qlonglong ll = numberStr.toLongLong(&ok);
return ok ? ll : QVariant(numberStr);
}
return i;
} else {
uint u = numberStr.toUInt(&ok);
if (!ok) {
qulonglong ull = numberStr.toULongLong(&ok);
return ok ? ull : QVariant(numberStr);
}
return u;
}
}
/**
* lastIndexOfNumber
*/
static int lastIndexOfNumber(const QString &json, int index) {
int lastIndex;
for(lastIndex = index; lastIndex < json.size(); lastIndex++) {
if (QString("0123456789+-.eE").indexOf(json[lastIndex]) == -1) {
break;
}
}
return lastIndex -1;
}
/**
* eatWhitespace
*/
static void eatWhitespace(const QString &json, int &index) {
for(; index < json.size(); index++) {
if (QString(" \t\n\r").indexOf(json[index]) == -1) {
break;
}
}
}
/**
* lookAhead
*/
static int lookAhead(const QString &json, int index) {
int saveIndex = index;
return nextToken(json, saveIndex);
}
/**
* nextToken
*/
static int nextToken(const QString &json, int &index) {
eatWhitespace(json, index);
if (index == json.size()) {
return JsonTokenNone;
}
QChar c = json[index];
index++;
switch(c.toLatin1()) {
case '{': return JsonTokenCurlyOpen;
case '}': return JsonTokenCurlyClose;
case '[': return JsonTokenSquaredOpen;
case ']': return JsonTokenSquaredClose;
case ',': return JsonTokenComma;
case '"': return JsonTokenString;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '-': return JsonTokenNumber;
case ':': return JsonTokenColon;
}
index--; // ^ WTF?
int remainingLength = json.size() - index;
// True
if (remainingLength >= 4) {
if (json[index] == 't' && json[index + 1] == 'r' &&
json[index + 2] == 'u' && json[index + 3] == 'e') {
index += 4;
return JsonTokenTrue;
}
}
// False
if (remainingLength >= 5) {
if (json[index] == 'f' && json[index + 1] == 'a' &&
json[index + 2] == 'l' && json[index + 3] == 's' &&
json[index + 4] == 'e') {
index += 5;
return JsonTokenFalse;
}
}
// Null
if (remainingLength >= 4) {
if (json[index] == 'n' && json[index + 1] == 'u' &&
json[index + 2] == 'l' && json[index + 3] == 'l') {
index += 4;
return JsonTokenNull;
}
}
return JsonTokenNone;
}
void setDateTimeFormat(const QString &format) {
dateTimeFormat = format;
}
void setDateFormat(const QString &format) {
dateFormat = format;
}
QString getDateTimeFormat() {
return dateTimeFormat;
}
QString getDateFormat() {
return dateFormat;
}
void setPrettySerialize(bool enabled) {
prettySerialize = enabled;
}
bool isPrettySerialize() {
return prettySerialize;
}
QQueue<BuilderJsonObject *> BuilderJsonObject::created_list;
BuilderJsonObject::BuilderJsonObject() {
// clean objects previous "created"
while (!BuilderJsonObject::created_list.isEmpty()) {
delete BuilderJsonObject::created_list.dequeue();
}
}
BuilderJsonObject::BuilderJsonObject(JsonObject &json) {
BuilderJsonObject();
obj = json;
}
BuilderJsonObject *BuilderJsonObject::set(const QString &key, const QVariant &value) {
obj[key] = value;
return this;
}
BuilderJsonObject *BuilderJsonObject::set(const QString &key, BuilderJsonObject *builder) {
return set(key, builder->create());
}
BuilderJsonObject *BuilderJsonObject::set(const QString &key, BuilderJsonArray *builder) {
return set(key, builder->create());
}
JsonObject BuilderJsonObject::create() {
BuilderJsonObject::created_list.enqueue(this);
return obj;
}
QQueue<BuilderJsonArray *> BuilderJsonArray::created_list;
BuilderJsonArray::BuilderJsonArray() {
// clean objects previous "created"
while (!BuilderJsonArray::created_list.isEmpty()) {
delete BuilderJsonArray::created_list.dequeue();
}
}
BuilderJsonArray::BuilderJsonArray(JsonArray &json) {
BuilderJsonArray();
array = json;
}
BuilderJsonArray *BuilderJsonArray::add(const QVariant &element) {
array.append(element);
return this;
}
BuilderJsonArray *BuilderJsonArray::add(BuilderJsonObject *builder) {
return add(builder->create());
}
BuilderJsonArray *BuilderJsonArray::add(BuilderJsonArray *builder) {
return add(builder->create());
}
JsonArray BuilderJsonArray::create() {
BuilderJsonArray::created_list.enqueue(this);
return array;
}
BuilderJsonObject *objectBuilder() {
return new BuilderJsonObject();
}
BuilderJsonObject *objectBuilder(JsonObject &json) {
return new BuilderJsonObject(json);
}
BuilderJsonArray *arrayBuilder() {
return new BuilderJsonArray();
}
BuilderJsonArray *arrayBuilder(JsonArray &json) {
return new BuilderJsonArray(json);
}
} //end namespace

View File

@@ -1,265 +0,0 @@
/**
* QtJson - A simple class for parsing JSON data into a QVariant hierarchies and vice-versa.
* Copyright (C) 2011 Eeli Reilin
*
* 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 3 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* \file json.h
*/
#ifndef JSON_H
#define JSON_H
#include <QVariant>
#include <QString>
#include <QQueue>
/**
* \namespace QtJson
* \brief A JSON data parser
*
* Json parses a JSON data into a QVariant hierarchy.
*/
namespace QtJson {
typedef QVariantMap JsonObject;
typedef QVariantList JsonArray;
/**
* Clone a JSON object (makes a deep copy)
*
* \param data The JSON object
*/
QVariant clone(const QVariant &data);
/**
* Insert value to JSON object (QVariantMap)
*
* \param v The JSON object
* \param key The key
* \param value The value
*/
void insert(QVariant &v, const QString &key, const QVariant &value);
/**
* Append value to JSON array (QVariantList)
*
* \param v The JSON array
* \param value The value
*/
void append(QVariant &v, const QVariant &value);
/**
* Parse a JSON string
*
* \param json The JSON data
*/
QVariant parse(const QString &json);
/**
* Parse a JSON string
*
* \param json The JSON data
* \param success The success of the parsing
*/
QVariant parse(const QString &json, bool &success);
/**
* This method generates a textual JSON representation
*
* \param data The JSON data generated by the parser.
*
* \return QByteArray Textual JSON representation in UTF-8
*/
QByteArray serialize(const QVariant &data);
/**
* This method generates a textual JSON representation
*
* \param data The JSON data generated by the parser.
* \param success The success of the serialization
*
* \return QByteArray Textual JSON representation in UTF-8
*/
QByteArray serialize(const QVariant &data, bool &success, int _level = 0);
/**
* This method generates a textual JSON representation
*
* \param data The JSON data generated by the parser.
*
* \return QString Textual JSON representation
*/
QString serializeStr(const QVariant &data);
/**
* This method generates a textual JSON representation
*
* \param data The JSON data generated by the parser.
* \param success The success of the serialization
*
* \return QString Textual JSON representation
*/
QString serializeStr(const QVariant &data, bool &success, int _level = 0);
/**
* This method sets date(time) format to be used for QDateTime::toString
* If QString is empty, Qt::TextDate is used.
*
* \param format The JSON data generated by the parser.
*/
void setDateTimeFormat(const QString& format);
void setDateFormat(const QString& format);
/**
* This method gets date(time) format to be used for QDateTime::toString
* If QString is empty, Qt::TextDate is used.
*/
QString getDateTimeFormat();
QString getDateFormat();
/**
* @brief setPrettySerialize enable/disabled pretty-print when serialize() a json
* @param enabled
*/
void setPrettySerialize(bool enabled);
/**
* @brief isPrettySerialize check if is enabled pretty-print when serialize() a json
* @return
*/
bool isPrettySerialize();
/**
* QVariant based Json object
*/
class Object : public QVariant {
template<typename T>
Object& insertKey(Object* ptr, const QString& key) {
T* p = (T*)ptr->data();
if (!p->contains(key)) p->insert(key, QVariant());
return *reinterpret_cast<Object*>(&p->operator[](key));
}
template<typename T>
void removeKey(Object *ptr, const QString& key) {
T* p = (T*)ptr->data();
p->remove(key);
}
public:
Object() : QVariant() {}
Object(const Object& ref) : QVariant(ref) {}
Object& operator=(const QVariant& rhs) {
/** It maybe more robust when running under Qt versions below 4.7 */
QObject * obj = qvariant_cast<QObject *>(rhs);
// setValue(rhs);
setValue(obj);
return *this;
}
Object& operator[](const QString& key) {
if (type() == QVariant::Map)
return insertKey<QVariantMap>(this, key);
else if (type() == QVariant::Hash)
return insertKey<QVariantHash>(this, key);
setValue(QVariantMap());
return insertKey<QVariantMap>(this, key);
}
const Object& operator[](const QString& key) const {
return const_cast<Object*>(this)->operator[](key);
}
void remove(const QString& key) {
if (type() == QVariant::Map)
removeKey<QVariantMap>(this, key);
else if (type() == QVariant::Hash)
removeKey<QVariantHash>(this, key);
}
};
class BuilderJsonArray;
/**
* @brief The BuilderJsonObject class
*/
class BuilderJsonObject {
public:
BuilderJsonObject();
BuilderJsonObject(JsonObject &json);
BuilderJsonObject *set(const QString &key, const QVariant &value);
BuilderJsonObject *set(const QString &key, BuilderJsonObject *builder);
BuilderJsonObject *set(const QString &key, BuilderJsonArray *builder);
JsonObject create();
private:
static QQueue<BuilderJsonObject *> created_list;
JsonObject obj;
};
/**
* @brief The BuilderJsonArray class
*/
class BuilderJsonArray {
public:
BuilderJsonArray();
BuilderJsonArray(JsonArray &json);
BuilderJsonArray *add(const QVariant &element);
BuilderJsonArray *add(BuilderJsonObject *builder);
BuilderJsonArray *add(BuilderJsonArray *builder);
JsonArray create();
private:
static QQueue<BuilderJsonArray *> created_list;
JsonArray array;
};
/**
* @brief Create a BuilderJsonObject
* @return
*/
BuilderJsonObject *objectBuilder();
/**
* @brief Create a BuilderJsonObject starting from copy of another json
* @return
*/
BuilderJsonObject *objectBuilder(JsonObject &json);
/**
* @brief Create a BuilderJsonArray
* @return
*/
BuilderJsonArray *arrayBuilder();
/**
* @brief Create a BuilderJsonArray starting from copy of another json
* @return
*/
BuilderJsonArray *arrayBuilder(JsonArray &json);
}
#endif //JSON_H

View File

@@ -1,7 +1,6 @@
#ifndef IOS_VPNPROTOCOL_H
#define IOS_VPNPROTOCOL_H
#include "platforms/ios/json.h"
#include "vpnprotocol.h"
#include "protocols/protocols_defs.h"
@@ -50,15 +49,17 @@ private:
bool m_isChangingState = false;
void setupWireguardProtocol(const QtJson::JsonObject& result);
void setupOpenVPNProtocol(const QtJson::JsonObject& result);
void setupShadowSocksProtocol(const QtJson::JsonObject& result);
void setupWireguardProtocol(const QJsonObject& rawConfig);
void setupOpenVPNProtocol(const QJsonObject& rawConfig);
void setupCloakProtocol(const QJsonObject& rawConfig);
void setupShadowSocksProtocol(const QJsonObject& rawConfig);
void launchWireguardTunnel(const QtJson::JsonObject &result);
void launchOpenVPNTunnel(const QtJson::JsonObject &result);
void launchShadowSocksTunnel(const QtJson::JsonObject &result);
void launchWireguardTunnel(const QJsonObject& rawConfig);
void launchOpenVPNTunnel(const QJsonObject& rawConfig);
void launchCloakTunnel(const QJsonObject& rawConfig);
void launchShadowSocksTunnel(const QJsonObject& rawConfig);
QString serializeSSConfig(const QtJson::JsonObject &ssConfig);
QString serializeSSConfig(const QJsonObject &ssConfig);
};

View File

@@ -35,34 +35,22 @@ IOSVpnProtocol* IOSVpnProtocol::instance() {
}
bool IOSVpnProtocol::initialize()
{
qDebug() << "Initializing Swift Controller";
qDebug() << "RECEIVED CONFIG FROM SERVER SIDE =>";
qDebug() << QJsonDocument(m_rawConfig).toJson();
if (!m_controller) {
bool ok;
QtJson::JsonObject result = QtJson::parse(QJsonDocument(m_rawConfig).toJson(), ok).toMap();
if(!ok) {
qDebug() << QString("An error occurred during parsing");
return false;
}
QString protoName = result["protocol"].toString();
qDebug() << "PROTOCOL: " << protoName;
{
if (!m_controller) {
QString protoName = m_rawConfig["protocol"].toString();
if (protoName == "wireguard") {
setupWireguardProtocol(result);
setupWireguardProtocol(m_rawConfig);
currentProto = amnezia::Proto::WireGuard;
} else if (protoName == "openvpn") {
setupOpenVPNProtocol(result);
setupOpenVPNProtocol(m_rawConfig);
currentProto = amnezia::Proto::OpenVpn;
} else if (protoName == "shadowsocks") {
setupShadowSocksProtocol(result);
setupShadowSocksProtocol(m_rawConfig);
currentProto = amnezia::Proto::ShadowSocks;
} else if (protoName == "cloak") {
setupCloakProtocol(m_rawConfig);
currentProto = amnezia::Proto::Cloak;
} else {
return false;
}
@@ -72,39 +60,39 @@ bool IOSVpnProtocol::initialize()
ErrorCode IOSVpnProtocol::start()
{
bool ok;
QtJson::JsonObject result = QtJson::parse(QJsonDocument(m_rawConfig).toJson(), ok).toMap();
qDebug() << "current protocol: " << currentProto;
qDebug() << "new protocol: " << m_protocol;
qDebug() << "config: " << result;
if(!ok) {
qDebug() << QString("An error occurred during config parsing");
return InternalError;
}
{
if (m_isChangingState)
return NoError;
QString protocol = result["protocol"].toString();
if (!m_controller)
initialize();
switch (m_protocol) {
case amnezia::Proto::Cloak:
if (currentProto != m_protocol) {
if (m_controller) {
stop();
initialize();
}
launchCloakTunnel(m_rawConfig);
currentProto = amnezia::Proto::OpenVpn;
return NoError;
}
initialize();
launchCloakTunnel(m_rawConfig);
break;
case amnezia::Proto::OpenVpn:
if (currentProto != m_protocol) {
if (m_controller) {
stop();
initialize();
}
launchOpenVPNTunnel(result);
launchOpenVPNTunnel(m_rawConfig);
currentProto = amnezia::Proto::OpenVpn;
return NoError;
}
initialize();
launchOpenVPNTunnel(result);
launchOpenVPNTunnel(m_rawConfig);
break;
case amnezia::Proto::WireGuard:
if (currentProto != m_protocol) {
@@ -112,12 +100,12 @@ ErrorCode IOSVpnProtocol::start()
stop();
initialize();
}
launchWireguardTunnel(result);
launchWireguardTunnel(m_rawConfig);
currentProto = amnezia::Proto::WireGuard;
return NoError;
}
initialize();
launchWireguardTunnel(result);
launchWireguardTunnel(m_rawConfig);
break;
case amnezia::Proto::ShadowSocks:
if (currentProto != m_protocol) {
@@ -125,12 +113,12 @@ ErrorCode IOSVpnProtocol::start()
stop();
initialize();
}
launchShadowSocksTunnel(result);
launchShadowSocksTunnel(m_rawConfig);
currentProto = amnezia::Proto::ShadowSocks;
return NoError;
}
initialize();
launchShadowSocksTunnel(result);
launchShadowSocksTunnel(m_rawConfig);
break;
default:
break;
@@ -143,11 +131,6 @@ void IOSVpnProtocol::stop()
{
if (!m_controller) {
qDebug() << "Not correctly initialized";
// dispatch_async(dispatch_get_main_queue(), ^{
// emit connectionStateChanged(Disconnected);
// });
return;
}
@@ -165,16 +148,12 @@ void IOSVpnProtocol::resume_start()
}
void IOSVpnProtocol::checkStatus()
{
qDebug() << "Checking status";
{
if (m_checkingStatus) {
qDebug() << "We are still waiting for the previous status.";
return;
}
if (!m_controller) {
qDebug() << "Not correctly initialized";
return;
}
@@ -206,9 +185,6 @@ void IOSVpnProtocol::checkStatus()
}
}
qDebug() << "ServerIpv4Gateway:" << QString::fromNSString(serverIpv4Gateway)
<< "DeviceIpv4Address:" << QString::fromNSString(deviceIpv4Address)
<< "RxBytes:" << rxBytes << "TxBytes:" << txBytes;
emit newTransmittedDataCount(rxBytes, txBytes);
}];
}
@@ -255,22 +231,18 @@ void IOSVpnProtocol::cleanupBackendLogs()
file.remove();
}
void IOSVpnProtocol::setupWireguardProtocol(const QtJson::JsonObject &result)
void IOSVpnProtocol::setupWireguardProtocol(const QJsonObject& rawConfig)
{
static bool creating = false;
// No nested creation!
Q_ASSERT(creating == false);
creating = true;
QtJson::JsonObject config = result["wireguard_config_data"].toMap();
QJsonObject config = rawConfig["wireguard_config_data"].toObject();
QString privateKey = config["client_priv_key"].toString();
QByteArray key = QByteArray::fromBase64(privateKey.toLocal8Bit());
qDebug() << " - " << "client_priv_key: " << config["client_priv_key"].toString();
qDebug() << " - " << "client_pub_key: " << config["client_pub_key"].toString();
qDebug() << " - " << "interface config: " << config["config"].toString();
QString addr = config["config"].toString().split("\n").takeAt(1).split(" = ").takeLast();
QString dns = config["config"].toString().split("\n").takeAt(2).split(" = ").takeLast();
QString privkey = config["config"].toString().split("\n").takeAt(3).split(" = ").takeLast();
@@ -279,25 +251,12 @@ void IOSVpnProtocol::setupWireguardProtocol(const QtJson::JsonObject &result)
QString allowedips = config["config"].toString().split("\n").takeAt(8).split(" = ").takeLast();
QString endpoint = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast();
QString keepalive = config["config"].toString().split("\n").takeAt(10).split(" = ").takeLast();
qDebug() << " - " << "[Interface] address: " << addr;
qDebug() << " - " << "[Interface] dns: " << dns;
qDebug() << " - " << "[Interface] private key: " << privkey;
qDebug() << " - " << "[Peer] public key: " << pubkey;
qDebug() << " - " << "[Peer] preshared key: " << presharedkey;
qDebug() << " - " << "[Peer] allowed ips: " << allowedips;
qDebug() << " - " << "[Peer] endpoint: " << endpoint;
qDebug() << " - " << "[Peer] keepalive: " << keepalive;
qDebug() << " - " << "hostName: " << config["hostName"].toString();
qDebug() << " - " << "psk_key: " << config["psk_key"].toString();
qDebug() << " - " << "server_pub_key: " << config["server_pub_key"].toString();
m_controller = [[IOSVpnProtocolImpl alloc] initWithBundleID:@VPN_NE_BUNDLEID
privateKey:key.toNSData()
deviceIpv4Address:addr.toNSString()
deviceIpv6Address:@"::/0"
closure:^(ConnectionState state, NSDate* date) {
qDebug() << "Creation completed with connection state:" << state;
creating = false;
switch (state) {
@@ -312,7 +271,6 @@ void IOSVpnProtocol::setupWireguardProtocol(const QtJson::JsonObject &result)
}
case ConnectionStateConnected: {
Q_ASSERT(date);
// QDateTime qtDate(QDateTime::fromNSDate(date));
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(VpnConnectionState::Connected);
m_isChangingState = false;
@@ -320,7 +278,6 @@ void IOSVpnProtocol::setupWireguardProtocol(const QtJson::JsonObject &result)
return;
}
case ConnectionStateDisconnected:
// Just in case we are connecting, let's call disconnect.
[m_controller disconnect];
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(VpnConnectionState::Disconnected);
@@ -349,16 +306,76 @@ void IOSVpnProtocol::setupWireguardProtocol(const QtJson::JsonObject &result)
}];
}
void IOSVpnProtocol::setupOpenVPNProtocol(const QtJson::JsonObject &result)
void IOSVpnProtocol::setupCloakProtocol(const QJsonObject &rawConfig)
{
static bool creating = false;
// No nested creation!
Q_ASSERT(creating == false);
creating = true;
QJsonObject ovpn = rawConfig["openvpn_config_data"].toObject();
QString ovpnConfig = ovpn["config"].toString();
m_controller = [[IOSVpnProtocolImpl alloc] initWithBundleID:@VPN_NE_BUNDLEID
config:ovpnConfig.toNSString()
closure:^(ConnectionState state, NSDate* date) {
creating = false;
switch (state) {
case ConnectionStateError: {
[m_controller dealloc];
m_controller = nullptr;
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(VpnConnectionState::Error);
m_isChangingState = false;
});
return;
}
case ConnectionStateConnected: {
Q_ASSERT(date);
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(VpnConnectionState::Connected);
m_isChangingState = false;
});
return;
}
case ConnectionStateDisconnected:
// Just in case we are connecting, let's call disconnect.
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(VpnConnectionState::Disconnected);
m_isChangingState = false;
});
return;
}
}
callback:^(BOOL a_connected) {
if (currentProto != m_protocol) {
qDebug() << "Protocols switched: " << a_connected;
return;
}
qDebug() << "VPN State changed: " << a_connected;
if (a_connected) {
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(Connected);
m_isChangingState = false;
});
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(Disconnected);
m_isChangingState = false;
});
}];
}
void IOSVpnProtocol::setupOpenVPNProtocol(const QJsonObject &rawConfig)
{
static bool creating = false;
// No nested creation!
Q_ASSERT(creating == false);
creating = true;
QtJson::JsonObject ovpn = result["openvpn_config_data"].toMap();
QJsonObject ovpn = rawConfig["openvpn_config_data"].toObject();
QString ovpnConfig = ovpn["config"].toString();
// qDebug() << ovpn;
m_controller = [[IOSVpnProtocolImpl alloc] initWithBundleID:@VPN_NE_BUNDLEID
config:ovpnConfig.toNSString()
@@ -378,7 +395,6 @@ void IOSVpnProtocol::setupOpenVPNProtocol(const QtJson::JsonObject &result)
}
case ConnectionStateConnected: {
Q_ASSERT(date);
// QDateTime qtDate(QDateTime::fromNSDate(date));
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(VpnConnectionState::Connected);
m_isChangingState = false;
@@ -387,7 +403,6 @@ void IOSVpnProtocol::setupOpenVPNProtocol(const QtJson::JsonObject &result)
}
case ConnectionStateDisconnected:
// Just in case we are connecting, let's call disconnect.
// [m_controller disconnect];
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(VpnConnectionState::Disconnected);
m_isChangingState = false;
@@ -400,7 +415,7 @@ void IOSVpnProtocol::setupOpenVPNProtocol(const QtJson::JsonObject &result)
qDebug() << "Protocols switched: " << a_connected;
return;
}
qDebug() << "OVPN State changed: " << a_connected;
qDebug() << "VPN State changed: " << a_connected;
if (a_connected) {
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(Connected);
@@ -415,23 +430,21 @@ void IOSVpnProtocol::setupOpenVPNProtocol(const QtJson::JsonObject &result)
}];
}
void IOSVpnProtocol::setupShadowSocksProtocol(const QtJson::JsonObject &result)
void IOSVpnProtocol::setupShadowSocksProtocol(const QJsonObject &rawConfig)
{
static bool creating = false;
// No nested creation!
Q_ASSERT(creating == false);
creating = true;
QtJson::JsonObject ovpn = result["openvpn_config_data"].toMap();
QJsonObject ovpn = rawConfig["openvpn_config_data"].toObject();
QString ovpnConfig = ovpn["config"].toString();
qDebug() << "OpenVPN Config:\n" << ovpn;
QtJson::JsonObject ssConfig = result["shadowsocks_config_data"].toMap();
QJsonObject ssConfig = rawConfig["shadowsocks_config_data"].toObject();
m_controller = [[IOSVpnProtocolImpl alloc] initWithBundleID:@VPN_NE_BUNDLEID
tunnelConfig:ovpnConfig.toNSString()
ssConfig:serializeSSConfig(ssConfig).toNSString()
closure:^(ConnectionState state, NSDate* date) {
qDebug() << "ShadowSocks creation completed with connection state:" << state;
creating = false;
switch (state) {
@@ -446,7 +459,6 @@ void IOSVpnProtocol::setupShadowSocksProtocol(const QtJson::JsonObject &result)
}
case ConnectionStateConnected: {
Q_ASSERT(date);
// QDateTime qtDate(QDateTime::fromNSDate(date));
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(VpnConnectionState::Connected);
m_isChangingState = false;
@@ -455,7 +467,6 @@ void IOSVpnProtocol::setupShadowSocksProtocol(const QtJson::JsonObject &result)
}
case ConnectionStateDisconnected:
// Just in case we are connecting, let's call disconnect.
// [m_controller disconnect];
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(VpnConnectionState::Disconnected);
m_isChangingState = false;
@@ -483,9 +494,9 @@ void IOSVpnProtocol::setupShadowSocksProtocol(const QtJson::JsonObject &result)
}];
}
void IOSVpnProtocol::launchWireguardTunnel(const QtJson::JsonObject &result)
void IOSVpnProtocol::launchWireguardTunnel(const QJsonObject &rawConfig)
{
QtJson::JsonObject config = result["wireguard_config_data"].toMap();
QJsonObject config = rawConfig["wireguard_config_data"].toObject();
QString clientPrivateKey = config["client_priv_key"].toString();
QByteArray key = QByteArray::fromBase64(clientPrivateKey.toLocal8Bit());
@@ -506,13 +517,6 @@ void IOSVpnProtocol::launchWireguardTunnel(const QtJson::JsonObject &result)
QString pskKey = config["psk_key"].toString();
QString serverPubKey = config["server_pub_key"].toString();
qDebug() << "IOSVPNProtocol starts for" << hostname;
qDebug() << "DNS:" << dnsServersList.takeFirst().toNSString();
qDebug() << "serverPublicKey:" << serverPubKey.toNSString();
qDebug() << "serverIpv4AddrIn:" << serverAddr.toNSString();
qDebug() << "serverPort:" << (uint32_t)port.toInt();
qDebug() << "allowed ip list" << allowedIPList;
NSMutableArray<VPNIPAddressRange*>* allowedIPAddressRangesNS =
[NSMutableArray<VPNIPAddressRange*> arrayWithCapacity:allowedIPList.length()];
for (const IPAddressRange item : allowedIPList) {
@@ -541,9 +545,56 @@ void IOSVpnProtocol::launchWireguardTunnel(const QtJson::JsonObject &result)
}];
}
void IOSVpnProtocol::launchOpenVPNTunnel(const QtJson::JsonObject &result)
void IOSVpnProtocol::launchCloakTunnel(const QJsonObject &rawConfig)
{
QJsonObject ovpn = rawConfig["openvpn_config_data"].toObject();
QString ovpnConfig = ovpn["config"].toString();
if(rawConfig["protocol"].toString() == "cloak"){
QJsonObject cloak = rawConfig["cloak_config_data"].toObject();
cloak["NumConn"] = 1;
cloak["RemoteHost"] = cloak["remote"].toString();
cloak["RemotePort"] = cloak["port"].toString();
cloak.remove("remote");
cloak.remove("port");
// Convert JSONObject to JSONDocument
QJsonObject jsonObject {};
foreach(const QString& key, cloak.keys()) {
if(key == "NumConn" or key == "StreamTimeout"){
jsonObject.insert(key, cloak.value(key).toInt());
}else{
jsonObject.insert(key, cloak.value(key).toString());
}
}
QJsonDocument doc(jsonObject);
QString strJson(doc.toJson(QJsonDocument::Compact));
QString cloakBase64 = strJson.toUtf8().toBase64();
ovpnConfig.append("\n<cloak>\n");
ovpnConfig.append(cloakBase64);
ovpnConfig.append("\n</cloak>\n");
}
[m_controller connectWithOvpnConfig:ovpnConfig.toNSString()
failureCallback:^{
qDebug() << "IOSVPNProtocol (OpenVPN Cloak) - connection failed";
dispatch_async(dispatch_get_main_queue(), ^{
emit connectionStateChanged(Disconnected);
m_isChangingState = false;
});
}];
}
void IOSVpnProtocol::launchOpenVPNTunnel(const QJsonObject &rawConfig)
{
QtJson::JsonObject ovpn = result["openvpn_config_data"].toMap();
QJsonObject ovpn = rawConfig["openvpn_config_data"].toObject();
QString ovpnConfig = ovpn["config"].toString();
[m_controller connectWithOvpnConfig:ovpnConfig.toNSString()
@@ -556,10 +607,10 @@ void IOSVpnProtocol::launchOpenVPNTunnel(const QtJson::JsonObject &result)
}];
}
void IOSVpnProtocol::launchShadowSocksTunnel(const QtJson::JsonObject &result) {
QtJson::JsonObject ovpn = result["openvpn_config_data"].toMap();
void IOSVpnProtocol::launchShadowSocksTunnel(const QJsonObject &rawConfig) {
QJsonObject ovpn = rawConfig["openvpn_config_data"].toObject();
QString ovpnConfig = ovpn["config"].toString();
QtJson::JsonObject ssConfig = result["shadowsocks_config_data"].toMap();
QJsonObject ssConfig = rawConfig["shadowsocks_config_data"].toObject();
QString ss = serializeSSConfig(ssConfig);
[m_controller connectWithSsConfig:ss.toNSString()
@@ -573,26 +624,18 @@ void IOSVpnProtocol::launchShadowSocksTunnel(const QtJson::JsonObject &result) {
}];
}
QString IOSVpnProtocol::serializeSSConfig(const QtJson::JsonObject &ssConfig) {
QString IOSVpnProtocol::serializeSSConfig(const QJsonObject &ssConfig) {
QString ssLocalPort = ssConfig["local_port"].toString();
QString ssMethod = ssConfig["method"].toString();
QString ssPassword = ssConfig["password"].toString();
QString ssServer = ssConfig["server"].toString();
QString ssPort = ssConfig["server_port"].toString();
QString ssTimeout = ssConfig["timeout"].toString();
qDebug() << "\n\nSS CONFIG:";
qDebug() << " local port -" << ssLocalPort;
qDebug() << " method -" << ssMethod;
qDebug() << " password -" << ssPassword;
qDebug() << " server -" << ssServer;
qDebug() << " port -" << ssPort;
qDebug() << " timeout -" << ssTimeout;
QJsonObject shadowSocksConfig = QJsonObject();
shadowSocksConfig.insert("local_addr", "127.0.0.1");
shadowSocksConfig.insert("local_port", ssConfig["local_port"].toInt());
shadowSocksConfig.insert("method", ssConfig["method"].toString());
// shadowSocksConfig.insert("method", "aes-256-gcm");
shadowSocksConfig.insert("password", ssConfig["password"].toString());
shadowSocksConfig.insert("server", ssConfig["server"].toString());
shadowSocksConfig.insert("server_port", ssConfig["server_port"].toInt());

View File

@@ -80,7 +80,6 @@ void VpnLogic::onUpdatePage()
set_labelCurrentDns(dns.first + ", " + dns.second);
}
set_isContainerSupportedByCurrentPlatform(ContainerProps::isSupportedByCurrentPlatform(selectedContainer));
if (!isContainerSupportedByCurrentPlatform()) {
set_labelErrorText(tr("AmneziaVPN not supporting selected protocol on this device. Select another protocol."));