Compare commits
58 Commits
dev-netada
...
2.0.10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5ef462937 | ||
|
|
eca397b45f | ||
|
|
4829c8b314 | ||
|
|
94d29796b8 | ||
|
|
a6a69ab1b6 | ||
|
|
912051637a | ||
|
|
c233f767f4 | ||
|
|
b63bf2465f | ||
|
|
505c9c6218 | ||
|
|
14350240eb | ||
|
|
cb21991efa | ||
|
|
49e58c25f2 | ||
|
|
ac6000a2ae | ||
|
|
6d1c9edc24 | ||
|
|
1a7fa3746d | ||
|
|
f7a57ffeb4 | ||
|
|
ad9d45a154 | ||
|
|
5fffb2afe3 | ||
|
|
1269114074 | ||
|
|
d24f6ae064 | ||
|
|
95fe09489c | ||
|
|
1a144da36d | ||
|
|
8e26da1759 | ||
|
|
daf53226c3 | ||
|
|
2b9e615e51 | ||
|
|
02acbecef5 | ||
|
|
8f28964ce2 | ||
|
|
495e74e2f0 | ||
|
|
8f23970ccc | ||
|
|
9ec39658fe | ||
|
|
9943e081d9 | ||
|
|
68a51c9c63 | ||
|
|
e7dd964825 | ||
|
|
f20134415e | ||
|
|
bd9b9600c1 | ||
|
|
5ae9873455 | ||
|
|
5776ca0384 | ||
|
|
f8f4b39965 | ||
|
|
1d51419a11 | ||
|
|
5e1ca0c19f | ||
|
|
b341224c92 | ||
|
|
3861f23af3 | ||
|
|
e7beff79d0 | ||
|
|
2380875cbf | ||
|
|
343e6a50df | ||
|
|
5aa47d35e7 | ||
|
|
313ceed1d0 | ||
|
|
ac07d62344 | ||
|
|
2db1bbae4b | ||
|
|
090e50e936 | ||
|
|
b6bab0c723 | ||
|
|
1a333f7968 | ||
|
|
87c00b3804 | ||
|
|
eba71469a4 | ||
|
|
4eef127744 | ||
|
|
1ce26b3ada | ||
|
|
e7092ae769 | ||
|
|
b8b0ffb626 |
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
deploy/data/windows/x64/tap/windows_7/OemVista.inf eol=crlf
|
||||
deploy/data/windows/x64/tap/windows_10/OemVista.inf eol=crlf
|
||||
deploy/data/windows/x32/tap/windows_7/OemVista.inf eol=crlf
|
||||
deploy/data/windows/x32/tap/windows_10/OemVista.inf eol=crlf
|
||||
1
.gitignore
vendored
@@ -47,6 +47,7 @@ client/amneziavpn_qml_plugin_import.cpp
|
||||
client/qmlcache_loader.cpp
|
||||
client/rep_ipc_interface_replica.h
|
||||
client/resources_qmlcache.qrc
|
||||
client/3rd/OpenVPNAdpter/build/
|
||||
|
||||
# QtCreator
|
||||
|
||||
|
||||
6
.gitmodules
vendored
@@ -7,3 +7,9 @@
|
||||
[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/ss-abramchuk/OpenVPNAdapter.git
|
||||
[submodule "client/3rd/qzxing"]
|
||||
path = client/3rd/qzxing
|
||||
url = https://github.com/ftylitak/qzxing.git
|
||||
|
||||
@@ -2,5 +2,5 @@ TEMPLATE = subdirs
|
||||
SUBDIRS = client
|
||||
|
||||
!ios:!android {
|
||||
SUBDIRS += service platform
|
||||
SUBDIRS += service
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
HEADERS += \
|
||||
3rd/AdpInfo/netadpinfo.h \
|
||||
|
||||
win32: {
|
||||
SOURCES += \
|
||||
3rd/AdpInfo/win_netadpinfo.cc \
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace adpinfo{
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// {false,""} - no error
|
||||
// {true,"descr"} - error with description
|
||||
using RET_TYPE = std::tuple<bool, std::string>;
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/*
|
||||
* Getting the route table
|
||||
*/
|
||||
typedef struct route_table{
|
||||
std::string szDestIp{};
|
||||
std::string szMaskIp{};
|
||||
std::string szGatewayIp{};
|
||||
std::string szInterfaceIp{};
|
||||
unsigned long ulIfIndex{};
|
||||
}route_table;
|
||||
std::vector</*std::tuple<std::string,std::string,std::string,std::string>*/route_table>get_route_table(std::string_view);
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/*
|
||||
* The object uses for collect the information about active network adapters/interfaces
|
||||
*/
|
||||
class NetAdpInfo final{
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
class Adapter{
|
||||
std::string name{};
|
||||
std::string descr{};
|
||||
std::string route{};
|
||||
std::string address{};
|
||||
std::string gateway{};
|
||||
public:
|
||||
explicit Adapter() = default;
|
||||
~Adapter() = default;
|
||||
|
||||
void set_name(std::string_view);
|
||||
std::string_view get_name()const;
|
||||
void set_description(std::string_view);
|
||||
std::string_view get_description()const;
|
||||
void set_route_gateway(std::string_view);
|
||||
std::string_view get_route_gateway()const;
|
||||
void set_local_address(std::string_view);
|
||||
std::string_view get_local_address()const;
|
||||
void set_local_gateway(std::string_view);
|
||||
std::string_view get_local_gateway()const;
|
||||
};
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
int16_t _index_of_adapter{};
|
||||
std::vector<std::shared_ptr<Adapter>>_adapters{};
|
||||
|
||||
RET_TYPE collect_adapters_data();
|
||||
|
||||
public:
|
||||
explicit NetAdpInfo() = default;
|
||||
~NetAdpInfo() = default;
|
||||
|
||||
RET_TYPE get_adapter_info(std::string_view );
|
||||
std::string_view get_adapter_route_gateway()const;
|
||||
std::string_view get_adapter_local_address()const;
|
||||
std::string_view get_adapter_local_gateway()const;
|
||||
|
||||
};
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
} //end namespace
|
||||
@@ -1,321 +0,0 @@
|
||||
#include "netadpinfo.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
|
||||
#include <windows.h>
|
||||
#include <iphlpapi.h>
|
||||
|
||||
#pragma comment(lib, "iphlpapi.lib")
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//static std::string convert_wide_to_ansi(const std::wstring& widestring) {
|
||||
// auto nchars = WideCharToMultiByte(
|
||||
// CP_ACP,
|
||||
// 0,
|
||||
// widestring.c_str(),
|
||||
// static_cast<int>(widestring.length() + 1),
|
||||
// nullptr,
|
||||
// 0,
|
||||
// nullptr,
|
||||
// nullptr);
|
||||
// std::string converted_string{};
|
||||
// converted_string.resize(nchars);
|
||||
// WideCharToMultiByte(CP_ACP,
|
||||
// 0,
|
||||
// widestring.c_str(),
|
||||
// -1,
|
||||
// &converted_string[0],
|
||||
// static_cast<int>(widestring.length()),
|
||||
// nullptr,
|
||||
// nullptr);
|
||||
// return converted_string;
|
||||
//}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//static std::string get_founded_route(std::string_view ip_address){
|
||||
|
||||
// MIB_IPFORWARDROW br{0};
|
||||
// ZeroMemory(&br, sizeof(MIB_IPFORWARDROW));
|
||||
// struct in_addr ia;
|
||||
// std::string sTmp{};
|
||||
// DWORD dwRes = GetBestRoute(inet_addr(ip_address.data()), 0, &br);
|
||||
// if( dwRes == NO_ERROR ){
|
||||
// ia.S_un.S_addr = (u_long) br.dwForwardDest;
|
||||
// sTmp = inet_ntoa(ia);
|
||||
// qDebug()<<"Best Route:"<< sTmp.data();
|
||||
// }
|
||||
// return sTmp;
|
||||
//}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
static std::string get_route_gateway()
|
||||
{
|
||||
std::string route_gateway{};
|
||||
PMIB_IPFORWARDTABLE pIpForwardTable{nullptr};
|
||||
DWORD dwSize = 0;
|
||||
BOOL bOrder = FALSE;
|
||||
|
||||
struct in_addr IpAddr;
|
||||
char szGatewayIp[128]{'\0'};
|
||||
|
||||
DWORD dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
|
||||
if (dwStatus == ERROR_INSUFFICIENT_BUFFER) {
|
||||
if (!(pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc(dwSize))) {
|
||||
return {"Out of memory"};
|
||||
}
|
||||
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
|
||||
}
|
||||
if (dwStatus != ERROR_SUCCESS) {
|
||||
if (pIpForwardTable)
|
||||
free(pIpForwardTable);
|
||||
return {"getIpForwardTable failed"};
|
||||
}
|
||||
const DWORD end = pIpForwardTable->dwNumEntries;
|
||||
for (DWORD i = 0; i < end; i++) {
|
||||
if (pIpForwardTable->table[i].dwForwardDest == 0) {
|
||||
IpAddr.S_un.S_addr =
|
||||
(u_long) pIpForwardTable->table[i].dwForwardNextHop;
|
||||
strcpy_s(szGatewayIp, sizeof (szGatewayIp), inet_ntoa(IpAddr));
|
||||
route_gateway = std::string(szGatewayIp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pIpForwardTable)
|
||||
free(pIpForwardTable);
|
||||
|
||||
return route_gateway;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
static std::string get_interface_ip(DWORD index){
|
||||
std::string _ipaddr{'\0'};
|
||||
std::vector<BYTE> buffer{};
|
||||
IP_ADAPTER_INFO *adapter_info{nullptr};
|
||||
DWORD result{ERROR_BUFFER_OVERFLOW};
|
||||
ULONG buffer_len = sizeof(IP_ADAPTER_INFO) * 10;
|
||||
while (result == ERROR_BUFFER_OVERFLOW){
|
||||
buffer.resize(buffer_len);
|
||||
adapter_info = reinterpret_cast<IP_ADAPTER_INFO*>(&buffer[0]);
|
||||
result = GetAdaptersInfo(adapter_info, &buffer_len);
|
||||
if (result == ERROR_NO_DATA){
|
||||
return _ipaddr;
|
||||
}
|
||||
}//end while
|
||||
if (result != NO_ERROR){
|
||||
return _ipaddr;
|
||||
}
|
||||
IP_ADAPTER_INFO *adapter_iterator = adapter_info;
|
||||
while(adapter_iterator){
|
||||
if (adapter_iterator->Index == index)
|
||||
break;
|
||||
adapter_iterator = adapter_iterator->Next;
|
||||
}//end while
|
||||
if ( adapter_iterator != nullptr || adapter_iterator != 0x0 || adapter_iterator != NULL )
|
||||
_ipaddr = std::string(adapter_iterator->IpAddressList.IpAddress.String, 16);
|
||||
else
|
||||
_ipaddr = "127.0.0.1";
|
||||
return _ipaddr;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
namespace adpinfo {
|
||||
|
||||
std::vector<route_table>get_route_table(std::string_view ipifaddrs){
|
||||
|
||||
/*std::tuple<std::string, std::string, std::string, std::string >*/
|
||||
std::vector<route_table>ret_table{};
|
||||
PMIB_IPFORWARDTABLE p_table{nullptr};
|
||||
struct in_addr ip_addr{};
|
||||
DWORD size{};
|
||||
p_table = (MIB_IPFORWARDTABLE *) HeapAlloc(GetProcessHeap(), 0, (sizeof (MIB_IPFORWARDTABLE)));
|
||||
if (p_table == nullptr)
|
||||
{
|
||||
return ret_table;
|
||||
}
|
||||
if (GetIpForwardTable(p_table, &size, 0) == ERROR_INSUFFICIENT_BUFFER) {
|
||||
HeapFree(GetProcessHeap(), 0, p_table);
|
||||
p_table = (MIB_IPFORWARDTABLE *) HeapAlloc(GetProcessHeap(), 0, size);
|
||||
if (p_table == nullptr) {
|
||||
return ret_table;
|
||||
}
|
||||
}
|
||||
DWORD ret = GetIpForwardTable(p_table, &size, 0);
|
||||
if (ret == NO_ERROR) {
|
||||
const int &numEntries = static_cast<int>(p_table->dwNumEntries);
|
||||
for (int i = 0; i <numEntries; ++i) {
|
||||
char szDestIp[128]{};
|
||||
char szMaskIp[128]{};
|
||||
char szGatewayIp[128]{};
|
||||
char szInterfaceIp[21]{};
|
||||
ip_addr.S_un.S_addr = (u_long) p_table->table[i].dwForwardDest;
|
||||
strcpy_s(szDestIp, sizeof (szDestIp), inet_ntoa(ip_addr));
|
||||
ip_addr.S_un.S_addr = (u_long) p_table->table[i].dwForwardMask;
|
||||
strcpy_s(szMaskIp, sizeof (szMaskIp), inet_ntoa(ip_addr));
|
||||
ip_addr.S_un.S_addr = (u_long) p_table->table[i].dwForwardNextHop;
|
||||
strcpy_s(szGatewayIp, sizeof (szGatewayIp), inet_ntoa(ip_addr));
|
||||
const auto &ifname = get_interface_ip(p_table->table[i].dwForwardIfIndex);
|
||||
const auto &ifnameSize = ifname.length() + 1;
|
||||
strcpy_s(szInterfaceIp, ifnameSize, ifname.data());
|
||||
if (ipifaddrs.length() == 0){
|
||||
//std::make_tuple(std::string(szDestIp), std::string(szMaskIp), std::string(szGatewayIp), std::string(szInterfaceIp));
|
||||
const route_table &mt = {
|
||||
std::string(szDestIp),
|
||||
std::string(szMaskIp),
|
||||
std::string(szGatewayIp),
|
||||
std::string(szInterfaceIp),
|
||||
p_table->table[i].dwForwardIfIndex
|
||||
};
|
||||
ret_table.emplace_back(mt);
|
||||
}else{
|
||||
bool in_not_empty = (ifname.find(ipifaddrs) != std::string::npos);
|
||||
//bool in_as_destIp = ( std::string(szDestIp).find(ipifaddrs) != std::string::npos);
|
||||
bool destIp_as_zero = (std::string(szDestIp).find("0.0.0.0") != std::string::npos);
|
||||
bool mask_as_zero = (std::string(szMaskIp).find("0.0.0.0") != std::string::npos);
|
||||
// bool ip_the_same = (
|
||||
// std::string(szDestIp).find(ipifaddrs) != std::string::npos &&
|
||||
// std::string(szDestIp).find(szGatewayIp) != std::string::npos &&
|
||||
// std::string(szDestIp).find(szInterfaceIp) != std::string::npos
|
||||
// );
|
||||
// bool not_default = (std::string(szDestIp).find("127.0.0.1") == std::string::npos);
|
||||
|
||||
if ( in_not_empty &&
|
||||
// in_as_destIp &&
|
||||
destIp_as_zero &&
|
||||
mask_as_zero//) || ( ip_the_same && not_default )
|
||||
)
|
||||
{
|
||||
// finded
|
||||
const route_table &mt = {
|
||||
std::string(szDestIp),
|
||||
std::string(szMaskIp),
|
||||
std::string(szGatewayIp),
|
||||
std::string(szInterfaceIp),
|
||||
p_table->table[i].dwForwardIfIndex
|
||||
};//std::make_tuple(std::string(szDestIp), std::string(szMaskIp), std::string(szGatewayIp), std::string(szInterfaceIp));
|
||||
ret_table.emplace_back(mt);
|
||||
}
|
||||
}
|
||||
}//end for
|
||||
}//end if
|
||||
return ret_table;
|
||||
}
|
||||
}//end namespace adpinfo
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
namespace adpinfo {
|
||||
|
||||
void NetAdpInfo::Adapter::set_name(std::string_view value){
|
||||
name = value;
|
||||
}
|
||||
std::string_view NetAdpInfo::Adapter::get_name()const{
|
||||
|
||||
return name;
|
||||
}
|
||||
void NetAdpInfo::Adapter::set_description(std::string_view value){
|
||||
descr = value;
|
||||
}
|
||||
std::string_view NetAdpInfo::Adapter::get_description()const{
|
||||
return descr;
|
||||
}
|
||||
void NetAdpInfo::Adapter::set_route_gateway(std::string_view value){
|
||||
route = value;
|
||||
}
|
||||
std::string_view NetAdpInfo::Adapter::get_route_gateway()const{
|
||||
return route;
|
||||
|
||||
}
|
||||
void NetAdpInfo::Adapter::set_local_address(std::string_view value){
|
||||
address = value;
|
||||
}
|
||||
std::string_view NetAdpInfo::Adapter::get_local_address()const{
|
||||
return address;
|
||||
}
|
||||
void NetAdpInfo::Adapter::set_local_gateway(std::string_view value){
|
||||
gateway = value;
|
||||
}
|
||||
std::string_view NetAdpInfo::Adapter::get_local_gateway()const{
|
||||
return gateway;
|
||||
}
|
||||
|
||||
RET_TYPE NetAdpInfo::collect_adapters_data(){
|
||||
_adapters.clear();
|
||||
std::vector<BYTE> buffer{};
|
||||
IP_ADAPTER_INFO *adapter_info{nullptr};
|
||||
DWORD result{ERROR_BUFFER_OVERFLOW};
|
||||
ULONG buffer_len = sizeof(IP_ADAPTER_INFO) * 10;
|
||||
while (result == ERROR_BUFFER_OVERFLOW){
|
||||
buffer.resize(buffer_len);
|
||||
adapter_info = reinterpret_cast<IP_ADAPTER_INFO*>(&buffer[0]);
|
||||
result = GetAdaptersInfo(adapter_info, &buffer_len);
|
||||
if (result == ERROR_NO_DATA){
|
||||
return {true, "GetAdaptersInfo return ERROR_NO_DATA"};
|
||||
}
|
||||
}//end while
|
||||
if (result != NO_ERROR){
|
||||
const std::string &error = "GetAdaptersInfo failed :" + std::to_string(result);
|
||||
return {true, error};
|
||||
}
|
||||
IP_ADAPTER_INFO *adapter_iterator = adapter_info;
|
||||
while(adapter_iterator){
|
||||
std::shared_ptr<Adapter>_tmp{std::make_shared<Adapter>()};
|
||||
_tmp->set_name(adapter_iterator->AdapterName);
|
||||
_tmp->set_description(adapter_iterator->Description);
|
||||
_tmp->set_local_address(adapter_iterator->IpAddressList.IpAddress.String);
|
||||
std::string lgw = adapter_iterator->GatewayList.IpAddress.String;
|
||||
// if (lgw.length() == 0 || lgw.find("0.0.0.0") != std::string::npos)
|
||||
// {
|
||||
// //lgw = get_founded_route("8.8.8.8");
|
||||
// if (adapter_iterator->DhcpEnabled == 1)
|
||||
// {
|
||||
// lgw = adapter_iterator->DhcpServer.IpAddress.String;
|
||||
// }
|
||||
// }
|
||||
_tmp->set_local_gateway(lgw);
|
||||
_tmp->set_route_gateway(get_route_gateway());
|
||||
_adapters.emplace_back(_tmp);
|
||||
adapter_iterator = adapter_iterator->Next;
|
||||
}
|
||||
return {false, ""};
|
||||
}
|
||||
|
||||
RET_TYPE NetAdpInfo::get_adapter_info(std::string_view _adapter_name){
|
||||
|
||||
_index_of_adapter = -1;
|
||||
const auto result{collect_adapters_data()};
|
||||
if (std::get<0>(result) == true){
|
||||
_index_of_adapter = -1;
|
||||
return result;
|
||||
}
|
||||
const int16_t &len = static_cast<int16_t>(_adapters.size());
|
||||
for (auto i = 0; i< len; ++i){
|
||||
auto adap_name = _adapters[i]->get_name();
|
||||
auto adap_desc = _adapters[i]->get_description();
|
||||
if ( adap_name.find(_adapter_name) != std::string::npos || adap_desc.find(_adapter_name) != std::string::npos ){
|
||||
_index_of_adapter = i;
|
||||
return {false, ""};
|
||||
}
|
||||
}
|
||||
return {true, "adapters no founded"};
|
||||
}
|
||||
|
||||
std::string_view NetAdpInfo::get_adapter_route_gateway()const{
|
||||
if (_index_of_adapter < 0)
|
||||
return "error adapter index";
|
||||
return _adapters.at(_index_of_adapter)->get_route_gateway();
|
||||
}
|
||||
std::string_view NetAdpInfo::get_adapter_local_address()const{
|
||||
if (_index_of_adapter < 0)
|
||||
return "error adapter index";
|
||||
return _adapters.at(_index_of_adapter)->get_local_address();
|
||||
}
|
||||
std::string_view NetAdpInfo::get_adapter_local_gateway()const{
|
||||
if (_index_of_adapter < 0)
|
||||
return "error adapter index";
|
||||
return _adapters.at(_index_of_adapter)->get_local_gateway();
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//std::string NetAdpInfo::get_system_route(){
|
||||
// return get_route_gateway();
|
||||
//}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
}// end namespace
|
||||
1
client/3rd/OpenVPNAdapter
Submodule
@@ -1,129 +0,0 @@
|
||||
|
||||
#if !defined(AFX_QR_ENCODE_H__AC886DF7_C0AE_4C9F_AC7A_FCDA8CB1DD37__INCLUDED_)
|
||||
#define AFX_QR_ENCODE_H__AC886DF7_C0AE_4C9F_AC7A_FCDA8CB1DD37__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
#define QR_LEVEL_L 0
|
||||
#define QR_LEVEL_M 1
|
||||
#define QR_LEVEL_Q 2
|
||||
#define QR_LEVEL_H 3
|
||||
|
||||
//
|
||||
#define QR_MODE_NUMERAL 0
|
||||
#define QR_MODE_ALPHABET 1
|
||||
#define QR_MODE_8BIT 2
|
||||
#define QR_MODE_KANJI 3
|
||||
|
||||
//
|
||||
#define QR_VRESION_S 0
|
||||
#define QR_VRESION_M 1
|
||||
#define QR_VRESION_L 2
|
||||
|
||||
#define MAX_ALLCODEWORD 3706
|
||||
#define MAX_DATACODEWORD 2956
|
||||
#define MAX_CODEBLOCK 153
|
||||
#define MAX_MODULESIZE 177
|
||||
|
||||
#define QR_MARGIN 0
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
typedef struct tagRS_BLOCKINFO
|
||||
{
|
||||
int ncRSBlock;
|
||||
int ncAllCodeWord;
|
||||
int ncDataCodeWord;
|
||||
|
||||
} RS_BLOCKINFO, *LPRS_BLOCKINFO;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct tagQR_VERSIONINFO
|
||||
{
|
||||
int nVersionNo;
|
||||
int ncAllCodeWord;
|
||||
|
||||
int ncDataCodeWord[4];
|
||||
|
||||
int ncAlignPoint;
|
||||
int nAlignPoint[6];
|
||||
|
||||
RS_BLOCKINFO RS_BlockInfo1[4];
|
||||
RS_BLOCKINFO RS_BlockInfo2[4];
|
||||
|
||||
} QR_VERSIONINFO, *LPQR_VERSIONINFO;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CQR_Encode
|
||||
{
|
||||
public:
|
||||
CQR_Encode();
|
||||
~CQR_Encode();
|
||||
|
||||
public:
|
||||
int m_nLevel;
|
||||
int m_nVersion;
|
||||
bool m_bAutoExtent;
|
||||
int m_nMaskingNo;
|
||||
|
||||
public:
|
||||
int m_nSymbleSize;
|
||||
unsigned char m_byModuleData[MAX_MODULESIZE][MAX_MODULESIZE]; // [x][y]
|
||||
|
||||
private:
|
||||
int m_ncDataCodeWordBit;
|
||||
unsigned char m_byDataCodeWord[MAX_DATACODEWORD];
|
||||
|
||||
int m_ncDataBlock;
|
||||
unsigned char m_byBlockMode[MAX_DATACODEWORD];
|
||||
int m_nBlockLength[MAX_DATACODEWORD];
|
||||
|
||||
int m_ncAllCodeWord;
|
||||
unsigned char m_byAllCodeWord[MAX_ALLCODEWORD];
|
||||
unsigned char m_byRSWork[MAX_CODEBLOCK];
|
||||
|
||||
public:
|
||||
bool EncodeData(int nLevel, int nVersion, bool bAutoExtent, int nMaskingNo, const char* lpsSource, int ncSource = 0);
|
||||
|
||||
private:
|
||||
int GetEncodeVersion(int nVersion, const char* lpsSource, int ncLength);
|
||||
bool EncodeSourceData(const char* lpsSource, int ncLength, int nVerGroup);
|
||||
|
||||
int GetBitLength(unsigned char nMode, int ncData, int nVerGroup);
|
||||
|
||||
int SetBitStream(int nIndex, unsigned short wData, int ncData);
|
||||
|
||||
bool IsNumeralData(unsigned char c);
|
||||
bool IsAlphabetData(unsigned char c);
|
||||
bool IsKanjiData(unsigned char c1, unsigned char c2);
|
||||
|
||||
unsigned char AlphabetToBinaly(unsigned char c);
|
||||
unsigned short KanjiToBinaly(unsigned short wc);
|
||||
|
||||
void GetRSCodeWord(unsigned char * lpbyRSWork, int ncDataCodeWord, int ncRSCodeWord);
|
||||
|
||||
private:
|
||||
void FormatModule();
|
||||
|
||||
void SetFunctionModule();
|
||||
void SetFinderPattern(int x, int y);
|
||||
void SetAlignmentPattern(int x, int y);
|
||||
void SetVersionPattern();
|
||||
void SetCodeWordPattern();
|
||||
void SetMaskingPattern(int nPatternNo);
|
||||
void SetFormatInfoPattern(int nPatternNo);
|
||||
int CountPenalty();
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // !defined(AFX_QR_ENCODE_H__AC886DF7_C0AE_4C9F_AC7A_FCDA8CB1DD37__INCLUDED_)
|
||||
@@ -1,5 +0,0 @@
|
||||
HEADERS += \
|
||||
3rd/QRCodeGenerator/QRCodeGenerator.h \
|
||||
|
||||
SOURCES += \
|
||||
3rd/QRCodeGenerator/QRCodeGenerator.cpp \
|
||||
@@ -11,7 +11,7 @@ win32 {
|
||||
-lcrypt32 \
|
||||
|
||||
!contains(QMAKE_TARGET.arch, x86_64) {
|
||||
INCLUDEPATH += $$PWD/windows/x86_64
|
||||
INCLUDEPATH += $$PWD/windows/x86
|
||||
HEADERS += $$PWD/windows/x86/botan_all.h
|
||||
SOURCES += $$PWD/windows/x86/botan_all.cpp
|
||||
}
|
||||
|
||||
@@ -940,8 +940,8 @@ void SshConnectionPrivate::connectToHost()
|
||||
this, &SshConnectionPrivate::handleSocketConnected);
|
||||
connect(m_socket, &QIODevice::readyRead,
|
||||
this, &SshConnectionPrivate::handleIncomingData);
|
||||
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this,
|
||||
SLOT(handleSocketError()));
|
||||
connect(m_socket, &QAbstractSocket::errorOccurred,
|
||||
this, &SshConnectionPrivate::handleSocketError);
|
||||
connect(m_socket, &QAbstractSocket::disconnected,
|
||||
this, &SshConnectionPrivate::handleSocketDisconnected);
|
||||
connect(&m_timeoutTimer, &QTimer::timeout, this, &SshConnectionPrivate::handleTimeout);
|
||||
|
||||
1
client/3rd/qzxing
Submodule
@@ -217,7 +217,9 @@ enum ConnectionState : NSInteger;
|
||||
SWIFT_CLASS("_TtC10AmneziaVPN18IOSVpnProtocolImpl")
|
||||
@interface IOSVpnProtocolImpl : NSObject
|
||||
- (nonnull instancetype)initWithBundleID:(NSString * _Nonnull)bundleID privateKey:(NSData * _Nonnull)privateKey deviceIpv4Address:(NSString * _Nonnull)deviceIpv4Address deviceIpv6Address:(NSString * _Nonnull)deviceIpv6Address closure:(void (^ _Nonnull)(enum ConnectionState, NSDate * _Nullable))closure callback:(void (^ _Nonnull)(BOOL))callback OBJC_DESIGNATED_INITIALIZER;
|
||||
- (nonnull instancetype)initWithBundleID:(NSString * _Nonnull)bundleID config:(NSString * _Nonnull)config closure:(void (^ _Nonnull)(enum ConnectionState, NSDate * _Nullable))closure callback:(void (^ _Nonnull)(BOOL))callback;
|
||||
- (void)connectWithDnsServer:(NSString * _Nonnull)dnsServer serverIpv6Gateway:(NSString * _Nonnull)serverIpv6Gateway serverPublicKey:(NSString * _Nonnull)serverPublicKey presharedKey:(NSString * _Nonnull)presharedKey serverIpv4AddrIn:(NSString * _Nonnull)serverIpv4AddrIn serverPort:(NSInteger)serverPort allowedIPAddressRanges:(NSArray<VPNIPAddressRange *> * _Nonnull)allowedIPAddressRanges ipv6Enabled:(Boolean)enabled reason:(NSInteger)reason failureCallback:(void (^ _Nonnull)(void))failureCallback;
|
||||
- (void)connectWithOvpnConfig:(NSString * _Nonnull)ovpnConfig failureCallback:(void (^ _Nonnull)(void))failureCallback;
|
||||
- (void)disconnect;
|
||||
- (void)checkStatusWithCallback:(void (^ _Nonnull)(NSString * _Nonnull, NSString * _Nonnull, NSString * _Nonnull))callback;
|
||||
- (nonnull instancetype)init SWIFT_UNAVAILABLE;
|
||||
@@ -230,8 +232,6 @@ typedef SWIFT_ENUM(NSInteger, ConnectionState, closed) {
|
||||
ConnectionStateDisconnected = 2,
|
||||
};
|
||||
|
||||
|
||||
|
||||
SWIFT_CLASS("_TtC10AmneziaVPN17VPNIPAddressRange")
|
||||
@interface VPNIPAddressRange : NSObject
|
||||
- (nonnull instancetype)initWithAddress:(NSString * _Nonnull)address networkPrefixLength:(uint8_t)networkPrefixLength isIpv6:(BOOL)isIpv6 OBJC_DESIGNATED_INITIALIZER;
|
||||
|
||||
@@ -1,40 +1,29 @@
|
||||
<?xml version="1.0"?>
|
||||
<manifest package="org.amnezia.vpn" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="-- %%INSERT_VERSION_NAME%% --" android:versionCode="-- %%INSERT_VERSION_CODE%% --" android:installLocation="auto">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
|
||||
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default features. -->
|
||||
<!-- %%INSERT_FEATURES -->
|
||||
|
||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||
<application
|
||||
android:hardwareAccelerated="true"
|
||||
android:name="org.qtproject.qt5.android.bindings.QtApplication"
|
||||
android:label="-- %%INSERT_APP_NAME%% --"
|
||||
android:extractNativeLibs="true"
|
||||
android:icon="@drawable/icon">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
|
||||
android:name="org.qtproject.qt5.android.bindings.QtActivity"
|
||||
|
||||
android:label="-- %%INSERT_APP_NAME%% --"
|
||||
android:screenOrientation="unspecified"
|
||||
android:launchMode="singleTop">
|
||||
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:extractNativeLibs="true" android:icon="@drawable/icon">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop" android:theme="@style/splashScreenTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
|
||||
<!-- Application arguments -->
|
||||
<!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
|
||||
<!-- Application arguments -->
|
||||
|
||||
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
|
||||
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
|
||||
<meta-data android:name="android.app.repository" android:value="default"/>
|
||||
@@ -42,7 +31,6 @@
|
||||
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
||||
<!-- Deploy Qt libs as part of package -->
|
||||
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
|
||||
|
||||
<!-- Run with local libs -->
|
||||
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
|
||||
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
|
||||
@@ -57,7 +45,6 @@
|
||||
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
||||
<meta-data android:value="@string/unsupported_android_version" android:name="android.app.unsupported_android_version"/>
|
||||
<!-- Messages maps -->
|
||||
|
||||
<!-- Splash screen -->
|
||||
<!-- Orientation-specific (portrait/landscape) data is checked first. If not available for current orientation,
|
||||
then android.app.splash_screen_drawable. For best results, use together with splash_screen_sticky and
|
||||
@@ -68,7 +55,6 @@
|
||||
<!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
|
||||
<!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
|
||||
<!-- Splash screen -->
|
||||
|
||||
<!-- Background running -->
|
||||
<!-- Warning: changing this value to true may cause unexpected crashes if the
|
||||
application still try to draw after
|
||||
@@ -76,11 +62,9 @@
|
||||
signal is sent! -->
|
||||
<meta-data android:name="android.app.background_running" android:value="false"/>
|
||||
<!-- Background running -->
|
||||
|
||||
<!-- auto screen scale factor -->
|
||||
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
|
||||
<!-- auto screen scale factor -->
|
||||
|
||||
<!-- extract android style -->
|
||||
<!-- available android:values :
|
||||
* default - In most cases this will be the same as "full", but it can also be something else if needed, e.g., for compatibility reasons
|
||||
@@ -91,24 +75,20 @@
|
||||
<meta-data android:name="android.app.extract_android_style" android:value="default"/>
|
||||
<!-- extract android style -->
|
||||
<meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/splashscreen"/>
|
||||
</activity>
|
||||
|
||||
<service android:name=".VPNService"
|
||||
|
||||
android:permission="android.permission.BIND_VPN_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.net.VpnService"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service android:name="org.amnezia.vpn.qt.VPNPermissionHelper"
|
||||
|
||||
android:permission="android.permission.BIND_VPN_SERVICE">
|
||||
</service>
|
||||
|
||||
|
||||
|
||||
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
|
||||
</activity>
|
||||
|
||||
<service android:name=".VPNService"
|
||||
android:process=":QtOnlyProcess"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.net.VpnService"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service android:name="org.amnezia.vpn.qt.VPNPermissionHelper"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE">
|
||||
</service>
|
||||
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -38,13 +38,9 @@ apply plugin: 'kotlinx-serialization'
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||
implementation 'androidx.core:core-ktx:1.1.0'
|
||||
implementation 'com.android.installreferrer:installreferrer:2.2'
|
||||
implementation 'com.android.billingclient:billing-ktx:4.0.0'
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0-alpha02"
|
||||
implementation "androidx.security:security-crypto:1.1.0-alpha03"
|
||||
implementation "androidx.security:security-identity-credential:1.0.0-alpha02"
|
||||
implementation 'com.adjust.sdk:adjust-android:4.28.2'
|
||||
implementation 'com.google.android.gms:play-services-ads-identifier:17.0.1'
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2"
|
||||
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.0.10"
|
||||
}
|
||||
@@ -106,8 +102,8 @@ android {
|
||||
resConfig "en"
|
||||
minSdkVersion = 24
|
||||
targetSdkVersion = 30
|
||||
versionCode 2 // Change to a higher number
|
||||
versionName "2.0.1" // Change to a higher number
|
||||
versionCode 10 // Change to a higher number
|
||||
versionName "2.0.10" // Change to a higher number
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
||||
@@ -37,12 +37,13 @@ class VPNService : android.net.VpnService() {
|
||||
SharedLibraryLoader.loadSharedLibrary(this, "ovpn3")
|
||||
Log.i(tag, "Loaded libs")
|
||||
Log.e(tag, "Wireguard Version ${wgVersion()}")
|
||||
mOpenVPNThreadv3 = OpenVPNThreadv3 (this)
|
||||
mOpenVPNThreadv3 = OpenVPNThreadv3(this)
|
||||
mAlreadyInitialised = true
|
||||
|
||||
}
|
||||
|
||||
override fun onUnbind(intent: Intent?): Boolean {
|
||||
Log.v(tag, "Got Unbind request")
|
||||
if (!isUp) {
|
||||
// If the Qt Client got closed while we were not connected
|
||||
// we do not need to stay as a foreground service.
|
||||
@@ -52,9 +53,9 @@ class VPNService : android.net.VpnService() {
|
||||
}
|
||||
|
||||
/**
|
||||
* EntryPoint for the Service, gets Called when AndroidController.cpp
|
||||
* calles bindService. Returns the [VPNServiceBinder] so QT can send Requests to it.
|
||||
*/
|
||||
* EntryPoint for the Service, gets Called when AndroidController.cpp
|
||||
* calles bindService. Returns the [VPNServiceBinder] so QT can send Requests to it.
|
||||
*/
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
Log.v(tag, "Got Bind request")
|
||||
init()
|
||||
@@ -62,10 +63,10 @@ class VPNService : android.net.VpnService() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Might be the entryPoint if the Service gets Started via an
|
||||
* Service Intent: Might be from Always-On-Vpn from Settings
|
||||
* or from Booting the device and having "connect on boot" enabled.
|
||||
*/
|
||||
* Might be the entryPoint if the Service gets Started via an
|
||||
* Service Intent: Might be from Always-On-Vpn from Settings
|
||||
* or from Booting the device and having "connect on boot" enabled.
|
||||
*/
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
init()
|
||||
intent?.let {
|
||||
@@ -84,28 +85,28 @@ class VPNService : android.net.VpnService() {
|
||||
Log.e(
|
||||
tag,
|
||||
"VPN service was triggered without defining a Server or having a tunnel"
|
||||
)
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
this.mConfig = JSONObject(lastConfString)
|
||||
)
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
this.mConfig = JSONObject(lastConfString)
|
||||
}
|
||||
|
||||
// Invoked when the application is revoked.
|
||||
// At this moment, the VPN interface is already deactivated by the system.
|
||||
override fun onRevoke() {
|
||||
this.turnOff()
|
||||
super.onRevoke()
|
||||
}
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
||||
var connectionTime: Long = 0
|
||||
// Invoked when the application is revoked.
|
||||
// At this moment, the VPN interface is already deactivated by the system.
|
||||
override fun onRevoke() {
|
||||
this.turnOff()
|
||||
super.onRevoke()
|
||||
}
|
||||
|
||||
var connectionTime: Long = 0
|
||||
get() {
|
||||
return mConnectionTime
|
||||
}
|
||||
|
||||
var isUp: Boolean
|
||||
var isUp: Boolean
|
||||
get() {
|
||||
return currentTunnelHandle >= 0
|
||||
}
|
||||
@@ -118,7 +119,7 @@ class VPNService : android.net.VpnService() {
|
||||
mBinder.dispatchEvent(VPNServiceBinder.EVENTS.disconnected, "")
|
||||
mConnectionTime = 0
|
||||
}
|
||||
val status: JSONObject
|
||||
val status: JSONObject
|
||||
get() {
|
||||
val deviceIpv4: String = ""
|
||||
return JSONObject().apply {
|
||||
@@ -128,299 +129,307 @@ class VPNService : android.net.VpnService() {
|
||||
putOpt("deviceIpv4", mConfig?.getJSONObject("device")?.getString("ipv4Address"))
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Checks if the VPN Permission is given.
|
||||
* If the permission is given, returns true
|
||||
* Requests permission and returns false if not.
|
||||
*/
|
||||
fun checkPermissions(): Boolean {
|
||||
// See https://developer.android.com/guide/topics/connectivity/vpn#connect_a_service
|
||||
// Call Prepare, if we get an Intent back, we dont have the VPN Permission
|
||||
// from the user. So we need to pass this to our main Activity and exit here.
|
||||
val intent = prepare(this)
|
||||
if (intent == null) {
|
||||
Log.e(tag, "VPN Permission Already Present")
|
||||
return true
|
||||
}
|
||||
Log.e(tag, "Requesting VPN Permission")
|
||||
return false
|
||||
}
|
||||
|
||||
fun turnOn(json: JSONObject?): Int {
|
||||
if (!checkPermissions()) {
|
||||
Log.e(tag, "turn on was called without no permissions present!")
|
||||
isUp = false
|
||||
return 0
|
||||
}
|
||||
Log.i(tag, "Permission okay")
|
||||
mConfig = json!!
|
||||
mProtocol = mConfig!!.getString("protocol")
|
||||
when (mProtocol) {
|
||||
"openvpn" -> startOpenVpn()
|
||||
"wireguard" -> startWireGuard()
|
||||
else -> {
|
||||
Log.e(tag, "No protocol")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
fun establish(): ParcelFileDescriptor? {
|
||||
mbuilder.allowFamily(OsConstants.AF_INET)
|
||||
mbuilder.allowFamily(OsConstants.AF_INET6)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) mbuilder.setMetered(false)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) setUnderlyingNetworks(null)
|
||||
|
||||
return mbuilder.establish()
|
||||
}
|
||||
|
||||
fun setMtu(mtu: Int) {
|
||||
mbuilder.setMtu(mtu)
|
||||
}
|
||||
|
||||
fun addAddress(ip: String, len: Int){
|
||||
Log.v(tag, "mbuilder.addAddress($ip, $len)")
|
||||
mbuilder.addAddress(ip, len)
|
||||
}
|
||||
|
||||
fun addRoute(ip: String, len: Int){
|
||||
Log.v(tag, "mbuilder.addRoute($ip, $len)")
|
||||
mbuilder.addRoute(ip, len)
|
||||
}
|
||||
|
||||
fun addDNS(ip: String){
|
||||
Log.v(tag, "mbuilder.addDnsServer($ip)")
|
||||
mbuilder.addDnsServer(ip)
|
||||
if ("samsung".equals(Build.BRAND) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
|
||||
mbuilder.addRoute(ip, 32)
|
||||
}
|
||||
}
|
||||
|
||||
fun setSessionName(name: String){
|
||||
Log.v(tag, "mbuilder.setSession($name)")
|
||||
mbuilder.setSession(name)
|
||||
}
|
||||
|
||||
fun addHttpProxy(host: String, port: Int): Boolean{
|
||||
val proxyInfo = ProxyInfo.buildDirectProxy(host, port)
|
||||
Log.v(tag, "mbuilder.addHttpProxy($host, $port)")
|
||||
mbuilder.setHttpProxy(proxyInfo)
|
||||
/*
|
||||
* Checks if the VPN Permission is given.
|
||||
* If the permission is given, returns true
|
||||
* Requests permission and returns false if not.
|
||||
*/
|
||||
fun checkPermissions(): Boolean {
|
||||
// See https://developer.android.com/guide/topics/connectivity/vpn#connect_a_service
|
||||
// Call Prepare, if we get an Intent back, we dont have the VPN Permission
|
||||
// from the user. So we need to pass this to our main Activity and exit here.
|
||||
val intent = prepare(this)
|
||||
if (intent == null) {
|
||||
Log.e(tag, "VPN Permission Already Present")
|
||||
return true
|
||||
}
|
||||
Log.e(tag, "Requesting VPN Permission")
|
||||
return false
|
||||
}
|
||||
|
||||
fun setDomain(domain: String) {
|
||||
Log.v(tag, "mbuilder.setDomain($domain)")
|
||||
mbuilder.addSearchDomain(domain)
|
||||
}
|
||||
|
||||
fun turnOff() {
|
||||
Log.v(tag, "Try to disable tunnel")
|
||||
when(mProtocol){
|
||||
"wireguard" -> wgTurnOff(currentTunnelHandle)
|
||||
"openvpn" -> ovpnTurnOff()
|
||||
else -> {
|
||||
Log.e(tag, "No protocol")
|
||||
}
|
||||
}
|
||||
currentTunnelHandle = -1
|
||||
stopForeground(true)
|
||||
|
||||
fun turnOn(json: JSONObject?): Int {
|
||||
if (!checkPermissions()) {
|
||||
Log.e(tag, "turn on was called without no permissions present!")
|
||||
isUp = false
|
||||
stopSelf();
|
||||
return 0
|
||||
}
|
||||
Log.i(tag, "Permission okay")
|
||||
mConfig = json!!
|
||||
mProtocol = mConfig!!.getString("protocol")
|
||||
when (mProtocol) {
|
||||
"openvpn" -> startOpenVpn()
|
||||
"wireguard" -> startWireGuard()
|
||||
else -> {
|
||||
Log.e(tag, "No protocol")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
NotificationUtil.show(this) // Go foreground
|
||||
return 1
|
||||
}
|
||||
|
||||
fun establish(): ParcelFileDescriptor? {
|
||||
mbuilder.allowFamily(OsConstants.AF_INET)
|
||||
mbuilder.allowFamily(OsConstants.AF_INET6)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) mbuilder.setMetered(false)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) setUnderlyingNetworks(null)
|
||||
|
||||
return mbuilder.establish()
|
||||
}
|
||||
|
||||
fun setMtu(mtu: Int) {
|
||||
mbuilder.setMtu(mtu)
|
||||
}
|
||||
|
||||
fun addAddress(ip: String, len: Int) {
|
||||
Log.v(tag, "mbuilder.addAddress($ip, $len)")
|
||||
mbuilder.addAddress(ip, len)
|
||||
}
|
||||
|
||||
fun addRoute(ip: String, len: Int) {
|
||||
Log.v(tag, "mbuilder.addRoute($ip, $len)")
|
||||
mbuilder.addRoute(ip, len)
|
||||
}
|
||||
|
||||
fun addDNS(ip: String) {
|
||||
Log.v(tag, "mbuilder.addDnsServer($ip)")
|
||||
mbuilder.addDnsServer(ip)
|
||||
if ("samsung".equals(Build.BRAND) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
mbuilder.addRoute(ip, 32)
|
||||
}
|
||||
}
|
||||
|
||||
fun setSessionName(name: String) {
|
||||
Log.v(tag, "mbuilder.setSession($name)")
|
||||
mbuilder.setSession(name)
|
||||
}
|
||||
|
||||
fun addHttpProxy(host: String, port: Int): Boolean {
|
||||
val proxyInfo = ProxyInfo.buildDirectProxy(host, port)
|
||||
Log.v(tag, "mbuilder.addHttpProxy($host, $port)")
|
||||
mbuilder.setHttpProxy(proxyInfo)
|
||||
return true
|
||||
}
|
||||
|
||||
fun setDomain(domain: String) {
|
||||
Log.v(tag, "mbuilder.setDomain($domain)")
|
||||
mbuilder.addSearchDomain(domain)
|
||||
}
|
||||
|
||||
fun turnOff() {
|
||||
Log.v(tag, "Try to disable tunnel")
|
||||
when (mProtocol) {
|
||||
"wireguard" -> wgTurnOff(currentTunnelHandle)
|
||||
"openvpn" -> ovpnTurnOff()
|
||||
else -> {
|
||||
Log.e(tag, "No protocol")
|
||||
}
|
||||
}
|
||||
currentTunnelHandle = -1
|
||||
stopForeground(true)
|
||||
|
||||
isUp = false
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
|
||||
private fun ovpnTurnOff() {
|
||||
mOpenVPNThreadv3?.stop()
|
||||
mOpenVPNThreadv3 = null
|
||||
Log.e(tag, "mOpenVPNThreadv3 stop!")
|
||||
}
|
||||
/**
|
||||
* Configures an Android VPN Service Tunnel
|
||||
* with a given Wireguard Config
|
||||
*/
|
||||
private fun setupBuilder(config: Config, builder: Builder) {
|
||||
// Setup Split tunnel
|
||||
for (excludedApplication in config.`interface`.excludedApplications)
|
||||
private fun ovpnTurnOff() {
|
||||
mOpenVPNThreadv3?.stop()
|
||||
mOpenVPNThreadv3 = null
|
||||
Log.e(tag, "mOpenVPNThreadv3 stop!")
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures an Android VPN Service Tunnel
|
||||
* with a given Wireguard Config
|
||||
*/
|
||||
private fun setupBuilder(config: Config, builder: Builder) {
|
||||
// Setup Split tunnel
|
||||
for (excludedApplication in config.`interface`.excludedApplications)
|
||||
builder.addDisallowedApplication(excludedApplication)
|
||||
|
||||
// Device IP
|
||||
for (addr in config.`interface`.addresses) builder.addAddress(addr.address, addr.mask)
|
||||
// DNS
|
||||
for (addr in config.`interface`.dnsServers) builder.addDnsServer(addr.hostAddress)
|
||||
// Add All routes the VPN may route tos
|
||||
for (peer in config.peers) {
|
||||
for (addr in peer.allowedIps) {
|
||||
builder.addRoute(addr.address, addr.mask)
|
||||
}
|
||||
// Device IP
|
||||
for (addr in config.`interface`.addresses) builder.addAddress(addr.address, addr.mask)
|
||||
// DNS
|
||||
for (addr in config.`interface`.dnsServers) builder.addDnsServer(addr.hostAddress)
|
||||
// Add All routes the VPN may route tos
|
||||
for (peer in config.peers) {
|
||||
for (addr in peer.allowedIps) {
|
||||
builder.addRoute(addr.address, addr.mask)
|
||||
}
|
||||
builder.allowFamily(OsConstants.AF_INET)
|
||||
builder.allowFamily(OsConstants.AF_INET6)
|
||||
builder.setMtu(config.`interface`.mtu.orElse(1280))
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) builder.setMetered(false)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) setUnderlyingNetworks(null)
|
||||
|
||||
builder.setBlocking(true)
|
||||
}
|
||||
builder.allowFamily(OsConstants.AF_INET)
|
||||
builder.allowFamily(OsConstants.AF_INET6)
|
||||
builder.setMtu(config.`interface`.mtu.orElse(1280))
|
||||
|
||||
/**
|
||||
* Gets config value for {key} from the Current
|
||||
* running Wireguard tunnel
|
||||
*/
|
||||
private fun getConfigValue(key: String): String? {
|
||||
if (!isUp) {
|
||||
return null
|
||||
}
|
||||
val config = wgGetConfig(currentTunnelHandle) ?: return null
|
||||
val lines = config.split("\n")
|
||||
for (line in lines) {
|
||||
val parts = line.split("=")
|
||||
val k = parts.first()
|
||||
val value = parts.last()
|
||||
if (key == k) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) builder.setMetered(false)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) setUnderlyingNetworks(null)
|
||||
|
||||
builder.setBlocking(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets config value for {key} from the Current
|
||||
* running Wireguard tunnel
|
||||
*/
|
||||
private fun getConfigValue(key: String): String? {
|
||||
if (!isUp) {
|
||||
return null
|
||||
}
|
||||
val config = wgGetConfig(currentTunnelHandle) ?: return null
|
||||
val lines = config.split("\n")
|
||||
for (line in lines) {
|
||||
val parts = line.split("=")
|
||||
val k = parts.first()
|
||||
val value = parts.last()
|
||||
if (key == k) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun parseConfigData(data: String): Map<String, Map<String, String>> {
|
||||
val parseData = mutableMapOf<String, Map<String, String>>()
|
||||
var currentSection: Pair<String, MutableMap<String, String>>? = null
|
||||
data.lines().forEach { line ->
|
||||
if (line.isNotEmpty()) {
|
||||
if (line.startsWith('[')) {
|
||||
currentSection?.let {
|
||||
parseData.put(it.first, it.second)
|
||||
}
|
||||
currentSection = line.substring(1, line.indexOfLast { it == ']' }) to mutableMapOf()
|
||||
} else {
|
||||
val parameter = line.split("=", limit = 2)
|
||||
currentSection!!.second.put(parameter.first().trim(), parameter.last().trim())
|
||||
private fun parseConfigData(data: String): Map<String, Map<String, String>> {
|
||||
val parseData = mutableMapOf<String, Map<String, String>>()
|
||||
var currentSection: Pair<String, MutableMap<String, String>>? = null
|
||||
data.lines().forEach { line ->
|
||||
if (line.isNotEmpty()) {
|
||||
if (line.startsWith('[')) {
|
||||
currentSection?.let {
|
||||
parseData.put(it.first, it.second)
|
||||
}
|
||||
currentSection =
|
||||
line.substring(1, line.indexOfLast { it == ']' }) to mutableMapOf()
|
||||
} else {
|
||||
val parameter = line.split("=", limit = 2)
|
||||
currentSection!!.second.put(parameter.first().trim(), parameter.last().trim())
|
||||
}
|
||||
}
|
||||
currentSection?.let {
|
||||
parseData.put(it.first, it.second)
|
||||
}
|
||||
currentSection?.let {
|
||||
parseData.put(it.first, it.second)
|
||||
}
|
||||
return parseData
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Wireguard [Config] from a [json] string -
|
||||
* The [json] will be created in AndroidVpnProtocol.cpp
|
||||
*/
|
||||
private fun buildWireugardConfig(obj: JSONObject): Config {
|
||||
val confBuilder = Config.Builder()
|
||||
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 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 {
|
||||
allowedIPList.forEach {
|
||||
val network = InetNetwork.parse(it.trim())
|
||||
peerBuilder.addAllowedIp(network)
|
||||
}
|
||||
return parseData
|
||||
}
|
||||
peerBuilder.setEndpoint(InetEndpoint.parse(peerConfig["Endpoint"]))
|
||||
peerConfig["PersistentKeepalive"]?.let {
|
||||
peerBuilder.setPersistentKeepalive(it.toInt())
|
||||
}
|
||||
confBuilder.addPeer(peerBuilder.build())
|
||||
|
||||
val ifaceBuilder = Interface.Builder()
|
||||
val ifaceConfig = config["Interface"]!!
|
||||
ifaceBuilder.parsePrivateKey(ifaceConfig["PrivateKey"])
|
||||
ifaceBuilder.addAddress(InetNetwork.parse(ifaceConfig["Address"]))
|
||||
ifaceConfig["DNS"]!!.split(",").forEach {
|
||||
ifaceBuilder.addDnsServer(InetNetwork.parse(it.trim()).address)
|
||||
}
|
||||
/*val jExcludedApplication = obj.getJSONArray("excludedApps")
|
||||
(0 until jExcludedApplication.length()).toList().forEach {
|
||||
val appName = jExcludedApplication.get(it).toString()
|
||||
ifaceBuilder.excludeApplication(appName)
|
||||
}*/
|
||||
confBuilder.setInterface(ifaceBuilder.build())
|
||||
|
||||
return confBuilder.build()
|
||||
}
|
||||
|
||||
fun getVpnConfig(): JSONObject {
|
||||
return mConfig!!
|
||||
}
|
||||
|
||||
private fun startOpenVpn() {
|
||||
mOpenVPNThreadv3 = OpenVPNThreadv3(this)
|
||||
Thread({
|
||||
mOpenVPNThreadv3?.run()
|
||||
}).start()
|
||||
}
|
||||
|
||||
private fun startWireGuard() {
|
||||
val wireguard_conf = buildWireugardConfig(mConfig!!)
|
||||
if (currentTunnelHandle != -1) {
|
||||
Log.e(tag, "Tunnel already up")
|
||||
// Turn the tunnel down because this might be a switch
|
||||
wgTurnOff(currentTunnelHandle)
|
||||
}
|
||||
val wgConfig: String = wireguard_conf!!.toWgUserspaceString()
|
||||
val builder = Builder()
|
||||
setupBuilder(wireguard_conf, builder)
|
||||
builder.setSession("avpn0")
|
||||
builder.establish().use { tun ->
|
||||
if (tun == null) return
|
||||
Log.i(tag, "Go backend " + wgVersion())
|
||||
currentTunnelHandle = wgTurnOn("avpn0", tun.detachFd(), wgConfig)
|
||||
}
|
||||
if (currentTunnelHandle < 0) {
|
||||
Log.e(tag, "Activation Error Code -> $currentTunnelHandle")
|
||||
isUp = false
|
||||
return
|
||||
}
|
||||
protect(wgGetSocketV4(currentTunnelHandle))
|
||||
protect(wgGetSocketV6(currentTunnelHandle))
|
||||
isUp = true
|
||||
|
||||
// Store the config in case the service gets
|
||||
// asked boot vpn from the OS
|
||||
val prefs = Prefs.get(this)
|
||||
prefs.edit()
|
||||
.putString("lastConf", mConfig.toString())
|
||||
.apply()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun startService(c: Context) {
|
||||
c.applicationContext.startService(
|
||||
Intent(c.applicationContext, VPNService::class.java).apply {
|
||||
putExtra("startOnly", true)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Wireguard [Config] from a [json] string -
|
||||
* The [json] will be created in AndroidVpnProtocol.cpp
|
||||
*/
|
||||
private fun buildWireugardConfig(obj: JSONObject): Config {
|
||||
val confBuilder = Config.Builder()
|
||||
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 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 {
|
||||
allowedIPList.forEach {
|
||||
val network = InetNetwork.parse(it.trim())
|
||||
peerBuilder.addAllowedIp(network)
|
||||
}
|
||||
}
|
||||
peerBuilder.setEndpoint(InetEndpoint.parse(peerConfig["Endpoint"]))
|
||||
peerConfig["PersistentKeepalive"]?.let {
|
||||
peerBuilder.setPersistentKeepalive(it.toInt())
|
||||
}
|
||||
confBuilder.addPeer(peerBuilder.build())
|
||||
@JvmStatic
|
||||
private external fun wgGetConfig(handle: Int): String?
|
||||
|
||||
val ifaceBuilder = Interface.Builder()
|
||||
val ifaceConfig = config["Interface"]!!
|
||||
ifaceBuilder.parsePrivateKey(ifaceConfig["PrivateKey"])
|
||||
ifaceBuilder.addAddress(InetNetwork.parse(ifaceConfig["Address"]))
|
||||
ifaceConfig["DNS"]!!.split(",").forEach {
|
||||
ifaceBuilder.addDnsServer(InetNetwork.parse(it.trim()).address)
|
||||
}
|
||||
/*val jExcludedApplication = obj.getJSONArray("excludedApps")
|
||||
(0 until jExcludedApplication.length()).toList().forEach {
|
||||
val appName = jExcludedApplication.get(it).toString()
|
||||
ifaceBuilder.excludeApplication(appName)
|
||||
}*/
|
||||
confBuilder.setInterface(ifaceBuilder.build())
|
||||
@JvmStatic
|
||||
private external fun wgGetSocketV4(handle: Int): Int
|
||||
|
||||
return confBuilder.build()
|
||||
}
|
||||
@JvmStatic
|
||||
private external fun wgGetSocketV6(handle: Int): Int
|
||||
|
||||
fun getVpnConfig(): JSONObject {
|
||||
return mConfig!!
|
||||
}
|
||||
@JvmStatic
|
||||
private external fun wgTurnOff(handle: Int)
|
||||
|
||||
private fun startOpenVpn() {
|
||||
mOpenVPNThreadv3 = OpenVPNThreadv3 (this)
|
||||
Thread ({
|
||||
mOpenVPNThreadv3?.run()
|
||||
}).start()
|
||||
}
|
||||
@JvmStatic
|
||||
private external fun wgTurnOn(ifName: String, tunFd: Int, settings: String): Int
|
||||
|
||||
private fun startWireGuard(){
|
||||
val wireguard_conf = buildWireugardConfig(mConfig!!)
|
||||
if (currentTunnelHandle != -1) {
|
||||
Log.e(tag, "Tunnel already up")
|
||||
// Turn the tunnel down because this might be a switch
|
||||
wgTurnOff(currentTunnelHandle)
|
||||
}
|
||||
val wgConfig: String = wireguard_conf!!.toWgUserspaceString()
|
||||
val builder = Builder()
|
||||
setupBuilder(wireguard_conf, builder)
|
||||
builder.setSession("avpn0")
|
||||
builder.establish().use { tun ->
|
||||
if (tun == null)return
|
||||
Log.i(tag, "Go backend " + wgVersion())
|
||||
currentTunnelHandle = wgTurnOn("avpn0", tun.detachFd(), wgConfig)
|
||||
}
|
||||
if (currentTunnelHandle < 0) {
|
||||
Log.e(tag, "Activation Error Code -> $currentTunnelHandle")
|
||||
isUp = false
|
||||
return
|
||||
}
|
||||
protect(wgGetSocketV4(currentTunnelHandle))
|
||||
protect(wgGetSocketV6(currentTunnelHandle))
|
||||
isUp = true
|
||||
|
||||
// Store the config in case the service gets
|
||||
// asked boot vpn from the OS
|
||||
val prefs = Prefs.get(this)
|
||||
prefs.edit()
|
||||
.putString("lastConf", mConfig.toString())
|
||||
.apply()
|
||||
|
||||
NotificationUtil.show(this) // Go foreground
|
||||
}
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun startService(c: Context) {
|
||||
c.applicationContext.startService(
|
||||
Intent(c.applicationContext, VPNService::class.java).apply {
|
||||
putExtra("startOnly", true)
|
||||
})
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private external fun wgGetConfig(handle: Int): String?
|
||||
@JvmStatic
|
||||
private external fun wgGetSocketV4(handle: Int): Int
|
||||
@JvmStatic
|
||||
private external fun wgGetSocketV6(handle: Int): Int
|
||||
@JvmStatic
|
||||
private external fun wgTurnOff(handle: Int)
|
||||
@JvmStatic
|
||||
private external fun wgTurnOn(ifName: String, tunFd: Int, settings: String): Int
|
||||
@JvmStatic
|
||||
private external fun wgVersion(): String?
|
||||
}
|
||||
}
|
||||
@JvmStatic
|
||||
private external fun wgVersion(): String?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.ftylitak.qzxing;
|
||||
|
||||
public class NativeFunctions {
|
||||
public static native void onPermissionsGranted();
|
||||
public static native void onPermissionsDenied();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.ftylitak.qzxing;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import org.qtproject.qt5.android.bindings.QtActivity;
|
||||
import static org.ftylitak.qzxing.Utilities.REQUEST_CAMERA;
|
||||
|
||||
public class QZXingLiveActivity extends QtActivity {
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode,
|
||||
String permissions[], int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_CAMERA: {
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (grantResults.length > 0
|
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
NativeFunctions.onPermissionsGranted();
|
||||
} else {
|
||||
NativeFunctions.onPermissionsDenied();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
client/android/src/org/ftylitak/qzxing/Utilities.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package org.ftylitak.qzxing;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageManager;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Utilities {
|
||||
|
||||
public static final int REQUEST_CAMERA = 0;
|
||||
|
||||
public static final String[] requiredPermissionsModifyPhoneState = {
|
||||
Manifest.permission.CAMERA,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
};
|
||||
|
||||
public static void checkAndRequestPermissionList(Activity activity, String[] permissions) {
|
||||
ArrayList<String> permissionsToRequest = new ArrayList<>();
|
||||
for (int i = 0; i < permissions.length; i++) {
|
||||
if (ContextCompat.checkSelfPermission(activity, permissions[i])
|
||||
!= PackageManager.PERMISSION_GRANTED)
|
||||
permissionsToRequest.add(permissions[i]);
|
||||
}
|
||||
|
||||
if (permissionsToRequest.size() != 0)
|
||||
ActivityCompat.requestPermissions(activity,
|
||||
permissionsToRequest.toArray(new String[0]),
|
||||
REQUEST_CAMERA);
|
||||
else
|
||||
NativeFunctions.onPermissionsGranted();
|
||||
}
|
||||
|
||||
public static void requestQZXingPermissions(Activity activity) {
|
||||
checkAndRequestPermissionList(activity, requiredPermissionsModifyPhoneState);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,19 +1,21 @@
|
||||
QT += widgets core gui network xml remoteobjects quick
|
||||
QT += widgets core gui network xml remoteobjects quick svg
|
||||
|
||||
TARGET = AmneziaVPN
|
||||
TEMPLATE = app
|
||||
#CONFIG += console
|
||||
|
||||
CONFIG += qtquickcompiler
|
||||
CONFIG += qzxing_multimedia \
|
||||
enable_decoder_qr_code \
|
||||
enable_encoder_qr_code
|
||||
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
include("3rd/QtSsh/src/ssh/qssh.pri")
|
||||
include("3rd/QtSsh/src/botan/botan.pri")
|
||||
!android:!ios:include("3rd/SingleApplication/singleapplication.pri")
|
||||
include("3rd/QRCodeGenerator/QRCodeGenerator.pri")
|
||||
include ("3rd/SortFilterProxyModel/SortFilterProxyModel.pri")
|
||||
include("3rd/AdpInfo/adpinfo.pri")
|
||||
include("3rd/QZXing/src/QZXing-components.pri")
|
||||
|
||||
INCLUDEPATH += $$PWD/3rd/OpenSSL/include
|
||||
DEPENDPATH += $$PWD/3rd/OpenSSL/include
|
||||
@@ -29,9 +31,7 @@ HEADERS += \
|
||||
containers/containers_defs.h \
|
||||
core/defs.h \
|
||||
core/errorstrings.h \
|
||||
core/ipcclient.h \
|
||||
configurators/openvpn_configurator.h \
|
||||
core/privileged_process.h \
|
||||
core/scripts_registry.h \
|
||||
core/server_defs.h \
|
||||
core/servercontroller.h \
|
||||
@@ -49,6 +49,7 @@ HEADERS += \
|
||||
ui/pages_logic/NetworkSettingsLogic.h \
|
||||
ui/pages_logic/NewServerProtocolsLogic.h \
|
||||
ui/pages_logic/PageLogicBase.h \
|
||||
ui/pages_logic/QrDecoderLogic.h \
|
||||
ui/pages_logic/ServerConfiguringProgressLogic.h \
|
||||
ui/pages_logic/ServerContainersLogic.h \
|
||||
ui/pages_logic/ServerListLogic.h \
|
||||
@@ -85,9 +86,7 @@ SOURCES += \
|
||||
configurators/wireguard_configurator.cpp \
|
||||
containers/containers_defs.cpp \
|
||||
core/errorstrings.cpp \
|
||||
core/ipcclient.cpp \
|
||||
configurators/openvpn_configurator.cpp \
|
||||
core/privileged_process.cpp \
|
||||
core/scripts_registry.cpp \
|
||||
core/server_defs.cpp \
|
||||
core/servercontroller.cpp \
|
||||
@@ -104,6 +103,7 @@ SOURCES += \
|
||||
ui/pages_logic/NetworkSettingsLogic.cpp \
|
||||
ui/pages_logic/NewServerProtocolsLogic.cpp \
|
||||
ui/pages_logic/PageLogicBase.cpp \
|
||||
ui/pages_logic/QrDecoderLogic.cpp \
|
||||
ui/pages_logic/ServerConfiguringProgressLogic.cpp \
|
||||
ui/pages_logic/ServerContainersLogic.cpp \
|
||||
ui/pages_logic/ServerListLogic.cpp \
|
||||
@@ -142,12 +142,14 @@ win32 {
|
||||
RC_FILE = platform_win/vpnclient.rc
|
||||
|
||||
HEADERS += \
|
||||
ui/framelesswindow.h \
|
||||
protocols/ikev2_vpn_protocol_windows.h \
|
||||
ui/framelesswindow.h
|
||||
|
||||
SOURCES += \
|
||||
protocols/ikev2_vpn_protocol_windows.cpp \
|
||||
ui/framelesswindow.cpp
|
||||
|
||||
VERSION = 1.0.0.0
|
||||
VERSION = 2.0.0.0
|
||||
QMAKE_TARGET_COMPANY = "AmneziaVPN"
|
||||
QMAKE_TARGET_PRODUCT = "AmneziaVPN"
|
||||
|
||||
@@ -194,22 +196,28 @@ linux:!android {
|
||||
}
|
||||
|
||||
win32|macx|linux:!android {
|
||||
DEFINES += AMNEZIA_DESKTOP
|
||||
|
||||
HEADERS += \
|
||||
core/ipcclient.h \
|
||||
core/privileged_process.h \
|
||||
ui/systemtray_notificationhandler.h \
|
||||
protocols/openvpnprotocol.h \
|
||||
protocols/ikev2_vpn_protocol.h \
|
||||
protocols/openvpnovercloakprotocol.h \
|
||||
protocols/shadowsocksvpnprotocol.h \
|
||||
protocols/wireguardprotocol.h \
|
||||
|
||||
SOURCES += \
|
||||
core/ipcclient.cpp \
|
||||
core/privileged_process.cpp \
|
||||
ui/systemtray_notificationhandler.cpp \
|
||||
protocols/openvpnprotocol.cpp \
|
||||
protocols/ikev2_vpn_protocol.cpp \
|
||||
protocols/openvpnovercloakprotocol.cpp \
|
||||
protocols/shadowsocksvpnprotocol.cpp \
|
||||
protocols/wireguardprotocol.cpp \
|
||||
|
||||
REPC_REPLICA += ../ipc/ipc_interface.rep
|
||||
REPC_REPLICA += ../ipc/ipc_process_interface.rep
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -219,11 +227,13 @@ android {
|
||||
INCLUDEPATH += platforms/android
|
||||
|
||||
HEADERS += \
|
||||
platforms/android/native.h \
|
||||
platforms/android/android_controller.h \
|
||||
platforms/android/android_notificationhandler.h \
|
||||
protocols/android_vpnprotocol.h
|
||||
|
||||
SOURCES += \
|
||||
platforms/android/native.cpp \
|
||||
platforms/android/android_controller.cpp \
|
||||
platforms/android/android_notificationhandler.cpp \
|
||||
protocols/android_vpnprotocol.cpp
|
||||
@@ -277,6 +287,11 @@ ios {
|
||||
LIBS += -framework StoreKit
|
||||
LIBS += -framework UserNotifications
|
||||
|
||||
# LIBS += $$PWD/3rd/OpenVPNAdapter/build/Debug-iphoneos/LZ4.framework
|
||||
# LIBS += $$PWD/3rd/OpenVPNAdapter/build/Debug-iphoneos/mbedTLS.framework
|
||||
# LIBS += $$PWD/3rd/OpenVPNAdapter/build/Debug-iphoneos/OpenVPNClient.framework
|
||||
# LIBS += $$PWD/3rd/OpenVPNAdapter/build/Debug-iphoneos/OpenVPNAdapter.framework
|
||||
|
||||
DEFINES += MVPN_IOS
|
||||
|
||||
HEADERS += \
|
||||
@@ -310,7 +325,7 @@ ios {
|
||||
QMAKE_DEVELOPMENT_TEAM = X7UJ388FXK
|
||||
QMAKE_PROVISIONING_PROFILE = f2fefb59-14aa-4aa9-ac14-1d5531b06dcc
|
||||
QMAKE_XCODE_CODE_SIGN_IDENTITY = "Apple Distribution"
|
||||
QMAKE_INFO_PLIST= $$PWD/ios/app/Info.plist
|
||||
QMAKE_INFO_PLIST = $$PWD/ios/app/Info.plist
|
||||
|
||||
XCODEBUILD_FLAGS += -allowProvisioningUpdates
|
||||
|
||||
@@ -353,6 +368,4 @@ ios {
|
||||
}
|
||||
|
||||
|
||||
REPC_REPLICA += ../ipc/ipc_interface.rep
|
||||
!ios: REPC_REPLICA += ../ipc/ipc_process_interface.rep
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
|
||||
connData.host = credentials.hostName;
|
||||
connData.clientId = Utils::getRandomString(16);
|
||||
connData.password = Utils::getRandomString(16);
|
||||
//connData.password = "";
|
||||
connData.password = "";
|
||||
|
||||
QString certFileName = "/opt/amnezia/ikev2/clients/" + connData.clientId + ".p12";
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "containers/containers_defs.h"
|
||||
#include "utils.h"
|
||||
|
||||
Settings &VpnConfigurator::m_settings()
|
||||
{
|
||||
@@ -41,24 +42,59 @@ QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentia
|
||||
}
|
||||
}
|
||||
|
||||
QString VpnConfigurator::processConfigWithLocalSettings(DockerContainer container, Proto proto, QString config)
|
||||
QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
|
||||
{
|
||||
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
|
||||
config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
|
||||
QPair<QString, QString> dns;
|
||||
|
||||
bool useAmneziaDns = m_settings().useAmneziaDns();
|
||||
const QJsonObject &server = m_settings().server(serverIndex);
|
||||
|
||||
dns.first = server.value(config_key::dns1).toString();
|
||||
dns.second = server.value(config_key::dns2).toString();
|
||||
|
||||
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();
|
||||
}
|
||||
if (dns.second.isEmpty() || !Utils::checkIPv4Format(dns.second)) {
|
||||
dns.second = m_settings().secondaryDns();
|
||||
}
|
||||
|
||||
qDebug() << "VpnConfigurator::getDnsForConfig" << dns.first << dns.second;
|
||||
return dns;
|
||||
}
|
||||
|
||||
QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerContainer container,
|
||||
Proto proto, QString &config)
|
||||
{
|
||||
auto dns = getDnsForConfig(serverIndex);
|
||||
|
||||
config.replace("$PRIMARY_DNS", dns.first);
|
||||
config.replace("$SECONDARY_DNS", dns.second);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, DockerContainer container,
|
||||
Proto proto, QString &config)
|
||||
{
|
||||
processConfigWithDnsSettings(serverIndex, container, proto, config);
|
||||
|
||||
if (proto == Proto::OpenVpn) {
|
||||
return OpenVpnConfigurator::processConfigWithLocalSettings(config);
|
||||
config = OpenVpnConfigurator::processConfigWithLocalSettings(config);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
QString VpnConfigurator::processConfigWithExportSettings(DockerContainer container, Proto proto, QString config)
|
||||
QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, DockerContainer container,
|
||||
Proto proto, QString &config)
|
||||
{
|
||||
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
|
||||
config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
|
||||
processConfigWithDnsSettings(serverIndex, container, proto, config);
|
||||
|
||||
if (proto == Proto::OpenVpn) {
|
||||
return OpenVpnConfigurator::processConfigWithExportSettings(config);
|
||||
config = OpenVpnConfigurator::processConfigWithExportSettings(config);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@ public:
|
||||
static QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr);
|
||||
|
||||
static QString processConfigWithLocalSettings(DockerContainer container, Proto proto, QString config);
|
||||
static QString processConfigWithExportSettings(DockerContainer container, Proto proto, QString config);
|
||||
static QPair<QString, QString> getDnsForConfig(int serverIndex);
|
||||
static QString &processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
|
||||
static QString &processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
static QString &processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
|
||||
// workaround for containers which is not support normal configaration
|
||||
static void updateContainerConfigAfterInstallation(DockerContainer container,
|
||||
|
||||
@@ -50,7 +50,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
|
||||
}
|
||||
|
||||
WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardConfig(const ServerCredentials &credentials,
|
||||
DockerContainer container, ErrorCode *errorCode)
|
||||
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
|
||||
{
|
||||
WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys();
|
||||
connData.host = credentials.hostName;
|
||||
@@ -61,6 +61,49 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
|
||||
}
|
||||
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
|
||||
// Get list of already created clients (only IP addreses)
|
||||
QString nextIpNumber;
|
||||
{
|
||||
QString script = QString("cat %1 | grep AllowedIPs").arg(amnezia::protocols::wireguard::serverConfigPath);
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
|
||||
stdOut += data + "\n";
|
||||
};
|
||||
|
||||
ServerController::runContainerScript(credentials, container, script, cbReadStdOut);
|
||||
stdOut.replace("AllowedIPs = ", "");
|
||||
stdOut.replace("/32", "");
|
||||
QStringList ips = stdOut.split("\n", Qt::SkipEmptyParts);
|
||||
|
||||
// Calc next IP address
|
||||
if (ips.isEmpty()) {
|
||||
nextIpNumber = "2";
|
||||
}
|
||||
else {
|
||||
int next = ips.last().split(".").last().toInt() + 1;
|
||||
if (next > 254) {
|
||||
if (errorCode) *errorCode = ErrorCode::AddressPoolError;
|
||||
return connData;
|
||||
}
|
||||
nextIpNumber = QString::number(next);
|
||||
}
|
||||
}
|
||||
|
||||
QString subnetIp = containerConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
|
||||
{
|
||||
QStringList l = subnetIp.split(".", Qt::SkipEmptyParts);
|
||||
if (l.isEmpty()) {
|
||||
if (errorCode) *errorCode = ErrorCode::AddressPoolError;
|
||||
return connData;
|
||||
}
|
||||
l.removeLast();
|
||||
l.append(nextIpNumber);
|
||||
|
||||
connData.clientIP = l.join(".");
|
||||
}
|
||||
|
||||
// Get keys
|
||||
connData.serverPubKey = ServerController::getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPublicKeyPath, &e);
|
||||
connData.serverPubKey.replace("\n", "");
|
||||
if (e) {
|
||||
@@ -76,18 +119,15 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
|
||||
return connData;
|
||||
}
|
||||
|
||||
|
||||
// Add client to config
|
||||
QString configPart = QString(
|
||||
"[Peer]\n"
|
||||
"PublicKey = %1\n"
|
||||
"PresharedKey = %2\n"
|
||||
"AllowedIPs = $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR\n\n").
|
||||
"AllowedIPs = %3/32\n\n").
|
||||
arg(connData.clientPubKey).
|
||||
arg(connData.pskKey);
|
||||
|
||||
configPart = ServerController::replaceVars(configPart, ServerController::genVarsForScript(credentials, container));
|
||||
|
||||
qDebug().noquote() << "Adding wg conf part to server" << configPart;
|
||||
arg(connData.pskKey).
|
||||
arg(connData.clientIP);
|
||||
|
||||
e = ServerController::uploadTextFileToContainer(container, credentials, configPart,
|
||||
protocols::wireguard::serverConfigPath, QSsh::SftpOverwriteMode::SftpAppendToExisting);
|
||||
@@ -116,12 +156,13 @@ QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &crede
|
||||
QString config = ServerController::replaceVars(amnezia::scriptData(ProtocolScriptType::wireguard_template, container),
|
||||
ServerController::genVarsForScript(credentials, container, containerConfig));
|
||||
|
||||
ConnectionData connData = prepareWireguardConfig(credentials, container, errorCode);
|
||||
ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode);
|
||||
if (errorCode && *errorCode) {
|
||||
return "";
|
||||
}
|
||||
|
||||
config.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", connData.clientPrivKey);
|
||||
config.replace("$WIREGUARD_CLIENT_IP", connData.clientIP);
|
||||
config.replace("$WIREGUARD_SERVER_PUBLIC_KEY", connData.serverPubKey);
|
||||
config.replace("$WIREGUARD_PSK", connData.pskKey);
|
||||
|
||||
@@ -130,6 +171,7 @@ QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &crede
|
||||
|
||||
jConfig[config_key::hostName] = connData.host;
|
||||
jConfig[config_key::client_priv_key] = connData.clientPrivKey;
|
||||
jConfig[config_key::client_ip] = connData.clientIP;
|
||||
jConfig[config_key::client_pub_key] = connData.clientPubKey;
|
||||
jConfig[config_key::psk_key] = connData.pskKey;
|
||||
jConfig[config_key::server_pub_key] = connData.serverPubKey;
|
||||
|
||||
@@ -15,6 +15,7 @@ public:
|
||||
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
|
||||
@@ -29,7 +30,7 @@ public:
|
||||
|
||||
private:
|
||||
static ConnectionData prepareWireguardConfig(const ServerCredentials &credentials,
|
||||
DockerContainer container, ErrorCode *errorCode = nullptr);
|
||||
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||
|
||||
static ConnectionData genClientKeys();
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ Proto ContainerProps::defaultProtocol(DockerContainer c)
|
||||
}
|
||||
}
|
||||
|
||||
bool ContainerProps::isWorkingOnPlatform(DockerContainer c)
|
||||
bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return true;
|
||||
@@ -148,7 +148,11 @@ bool ContainerProps::isWorkingOnPlatform(DockerContainer c)
|
||||
default: return false;
|
||||
}
|
||||
#elif defined (Q_OS_MAC)
|
||||
return false;
|
||||
switch (c) {
|
||||
case DockerContainer::WireGuard: return false;
|
||||
case DockerContainer::Ipsec: return false;
|
||||
default: return true;
|
||||
}
|
||||
|
||||
#elif defined (Q_OS_ANDROID)
|
||||
switch (c) {
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
// it may be changed fot future containers :)
|
||||
Q_INVOKABLE static Proto defaultProtocol(DockerContainer c);
|
||||
|
||||
Q_INVOKABLE static bool isWorkingOnPlatform(DockerContainer c);
|
||||
Q_INVOKABLE static bool isSupportedByCurrentPlatform(DockerContainer c);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
namespace amnezia {
|
||||
|
||||
constexpr const qint16 qrMagicCode = 1984;
|
||||
|
||||
struct ServerCredentials
|
||||
{
|
||||
QString hostName;
|
||||
@@ -58,6 +60,7 @@ enum ErrorCode
|
||||
OpenVpnAdaptersInUseError,
|
||||
OpenVpnUnknownError,
|
||||
OpenVpnTapAdapterError,
|
||||
AddressPoolError,
|
||||
|
||||
// 3rd party utils errors
|
||||
OpenSslFailed,
|
||||
|
||||
@@ -45,6 +45,7 @@ QString errorString(ErrorCode code){
|
||||
// VPN errors
|
||||
case (OpenVpnAdaptersInUseError): return QObject::tr("Can't connect: another VPN connection is active");
|
||||
case (OpenVpnTapAdapterError): return QObject::tr("Can't setup OpenVPN TAP network adapter");
|
||||
case (AddressPoolError): return QObject::tr("VPN pool error: no available addresses");
|
||||
|
||||
case(InternalError):
|
||||
default:
|
||||
|
||||
@@ -65,7 +65,6 @@ bool IpcClient::init(IpcClient *instance)
|
||||
|
||||
QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
|
||||
{
|
||||
#ifndef Q_OS_IOS
|
||||
if (! Instance()->m_ipcClient || ! Instance()->m_ipcClient->isReplicaValid()) {
|
||||
qWarning() << "IpcClient::createPrivilegedProcess : IpcClient IpcClient replica is not valid";
|
||||
return nullptr;
|
||||
@@ -107,9 +106,6 @@ QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
|
||||
|
||||
auto proccessReplica = QSharedPointer<PrivilegedProcess>(pd->ipcProcess);
|
||||
return proccessReplica;
|
||||
#else
|
||||
return QSharedPointer<PrivilegedProcess>();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "privileged_process.h"
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
PrivilegedProcess::PrivilegedProcess() :
|
||||
IpcProcessInterfaceReplica()
|
||||
{
|
||||
@@ -26,4 +25,3 @@ void PrivilegedProcess::waitForFinished(int msecs)
|
||||
|
||||
loop->exec();
|
||||
}
|
||||
#endif // Q_OS_IOS
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
#include "rep_ipc_process_interface_replica.h"
|
||||
// This class is dangerous - instance of this class casted from base class,
|
||||
// so it support only functions
|
||||
@@ -20,11 +19,6 @@ public:
|
||||
|
||||
};
|
||||
|
||||
#else // defined Q_OS_IOS
|
||||
class IpcProcessInterfaceReplica {};
|
||||
class PrivilegedProcess {};
|
||||
#endif // Q_OS_IOS
|
||||
|
||||
#endif // PRIVILEGED_PROCESS_H
|
||||
|
||||
|
||||
|
||||
@@ -79,6 +79,8 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
|
||||
}
|
||||
|
||||
qDebug().noquote() << "EXEC" << lineToExec;
|
||||
Debug::appendSshLog("Run command:" + lineToExec);
|
||||
|
||||
QSharedPointer<SshRemoteProcess> proc = client->createRemoteProcess(lineToExec.toUtf8());
|
||||
|
||||
if (!proc) {
|
||||
@@ -101,7 +103,9 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
|
||||
|
||||
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardOutput, &wait, [proc, cbReadStdOut](){
|
||||
QString s = proc->readAllStandardOutput();
|
||||
|
||||
if (s != "." && !s.isEmpty()) {
|
||||
Debug::appendSshLog("Output: " + s);
|
||||
qDebug().noquote() << "stdout" << s;
|
||||
}
|
||||
if (cbReadStdOut) cbReadStdOut(s, proc);
|
||||
@@ -110,6 +114,7 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
|
||||
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, &wait, [proc, cbReadStdErr](){
|
||||
QString s = proc->readAllStandardError();
|
||||
if (s != "." && !s.isEmpty()) {
|
||||
Debug::appendSshLog("Output: " + s);
|
||||
qDebug().noquote() << "stderr" << s;
|
||||
}
|
||||
if (cbReadStdErr) cbReadStdErr(s, proc);
|
||||
@@ -135,6 +140,7 @@ ErrorCode ServerController::runContainerScript(const ServerCredentials &credenti
|
||||
const std::function<void (const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr)
|
||||
{
|
||||
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
|
||||
Debug::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + ":\n" + script);
|
||||
|
||||
ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName);
|
||||
if (e) return e;
|
||||
@@ -165,8 +171,9 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
|
||||
};
|
||||
|
||||
// mkdir
|
||||
QFileInfo fi(path);
|
||||
QString mkdir = "sudo docker exec -i $CONTAINER_NAME mkdir -p " + fi.absoluteDir().absolutePath();
|
||||
QString mkdir = QString("sudo docker exec -i $CONTAINER_NAME mkdir -p \"$(dirname %1)\"")
|
||||
.arg(path);
|
||||
|
||||
e = runScript(credentials,
|
||||
replaceVars(mkdir, genVarsForScript(credentials, container)));
|
||||
if (e) return e;
|
||||
@@ -477,8 +484,10 @@ QJsonObject ServerController::createContainerInitialConfig(DockerContainer conta
|
||||
|
||||
bool ServerController::isReinstallContainerRequred(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig)
|
||||
{
|
||||
const QJsonObject &oldProtoConfig = oldConfig[ContainerProps::containerToString(container)].toObject();
|
||||
const QJsonObject &newProtoConfig = newConfig[ContainerProps::containerToString(container)].toObject();
|
||||
Proto mainProto = ContainerProps::defaultProtocol(container);
|
||||
|
||||
const QJsonObject &oldProtoConfig = oldConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
|
||||
const QJsonObject &newProtoConfig = newConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
|
||||
|
||||
if (container == DockerContainer::OpenVpn) {
|
||||
if (oldProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) !=
|
||||
@@ -666,9 +675,9 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
|
||||
vars.append({{"$FAKE_WEB_SITE_ADDRESS", cloakConfig.value(config_key::site).toString(protocols::cloak::defaultRedirSite) }});
|
||||
|
||||
// Wireguard vars
|
||||
vars.append({{"$WIREGUARD_SUBNET_IP", openvpnConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) }});
|
||||
vars.append({{"$WIREGUARD_SUBNET_CIDR", openvpnConfig.value(config_key::subnet_cidr).toString(protocols::wireguard::defaultSubnetCidr) }});
|
||||
vars.append({{"$WIREGUARD_SUBNET_MASK", openvpnConfig.value(config_key::subnet_mask).toString(protocols::wireguard::defaultSubnetMask) }});
|
||||
vars.append({{"$WIREGUARD_SUBNET_IP", wireguarConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) }});
|
||||
vars.append({{"$WIREGUARD_SUBNET_CIDR", wireguarConfig.value(config_key::subnet_cidr).toString(protocols::wireguard::defaultSubnetCidr) }});
|
||||
vars.append({{"$WIREGUARD_SUBNET_MASK", wireguarConfig.value(config_key::subnet_mask).toString(protocols::wireguard::defaultSubnetMask) }});
|
||||
|
||||
vars.append({{"$WIREGUARD_SERVER_PORT", wireguarConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) }});
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <QObject>
|
||||
#include "sshconnection.h"
|
||||
#include "sshremoteprocess.h"
|
||||
#include "debug.h"
|
||||
#include "defs.h"
|
||||
#include "settings.h"
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QDir>
|
||||
@@ -10,9 +11,13 @@
|
||||
#include "defines.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
#include <core/ipcclient.h>
|
||||
#endif
|
||||
|
||||
QFile Debug::m_file;
|
||||
QTextStream Debug::m_textStream;
|
||||
QString Debug::m_logFileName;
|
||||
QString Debug::m_logFileName = QString("%1.log").arg(APPLICATION_NAME);
|
||||
|
||||
void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
|
||||
{
|
||||
@@ -26,10 +31,30 @@ void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons
|
||||
}
|
||||
|
||||
Debug::m_textStream << qFormatLogMessage(type, context, msg) << endl << flush;
|
||||
Debug::appendAllLog(qFormatLogMessage(type, context, msg));
|
||||
|
||||
std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush;
|
||||
}
|
||||
|
||||
Debug &Debug::Instance()
|
||||
{
|
||||
static Debug s;
|
||||
return s;
|
||||
}
|
||||
|
||||
void Debug::appendSshLog(const QString &log)
|
||||
{
|
||||
QString dt = QDateTime::currentDateTime().toString();
|
||||
Instance().m_sshLog.append(dt + ": " + log + "\n");
|
||||
emit Instance().sshLogChanged(Instance().sshLog());
|
||||
}
|
||||
|
||||
void Debug::appendAllLog(const QString &log)
|
||||
{
|
||||
Instance().m_allLog.append(log + "\n");
|
||||
emit Instance().allLogChanged(Instance().allLog());
|
||||
}
|
||||
|
||||
bool Debug::init()
|
||||
{
|
||||
qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} %{type} %{message}");
|
||||
@@ -40,11 +65,8 @@ bool Debug::init()
|
||||
return false;
|
||||
}
|
||||
|
||||
m_logFileName = QString("%1.log").arg(APPLICATION_NAME);
|
||||
|
||||
|
||||
m_file.setFileName(appDir.filePath(m_logFileName));
|
||||
if (!m_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
if (!m_file.open(QIODevice::Append)) {
|
||||
qWarning() << "Cannot open log file:" << m_logFileName;
|
||||
return false;
|
||||
}
|
||||
@@ -63,6 +85,20 @@ QString Debug::userLogsDir()
|
||||
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/log";
|
||||
}
|
||||
|
||||
QString Debug::userLogsFilePath()
|
||||
{
|
||||
return userLogsDir() + QDir::separator() + m_logFileName;
|
||||
}
|
||||
|
||||
QString Debug::getLogFile()
|
||||
{
|
||||
m_file.flush();
|
||||
QFile file(userLogsFilePath());
|
||||
|
||||
file.open(QIODevice::ReadOnly);
|
||||
return file.readAll();
|
||||
}
|
||||
|
||||
bool Debug::openLogsFolder()
|
||||
{
|
||||
QString path = userLogsDir();
|
||||
@@ -88,3 +124,50 @@ QString Debug::appLogFileNamePath()
|
||||
{
|
||||
return m_file.fileName();
|
||||
}
|
||||
|
||||
void Debug::clearLogs()
|
||||
{
|
||||
bool isLogActive = m_file.isOpen();
|
||||
m_file.close();
|
||||
|
||||
QFile file(userLogsFilePath());
|
||||
|
||||
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
||||
file.resize(0);
|
||||
file.close();
|
||||
|
||||
if (isLogActive) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
void Debug::clearServiceLogs()
|
||||
{
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
IpcClient *m_IpcClient = new IpcClient;
|
||||
|
||||
if (!m_IpcClient->isSocketConnected()) {
|
||||
if (!IpcClient::init(m_IpcClient)) {
|
||||
qWarning() << "Error occured when init IPC client";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_IpcClient->Interface()) {
|
||||
m_IpcClient->Interface()->setLogsEnabled(false);
|
||||
m_IpcClient->Interface()->cleanUp();
|
||||
}
|
||||
else {
|
||||
qWarning() << "Error occured cleaning up service logs";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Debug::cleanUp()
|
||||
{
|
||||
clearLogs();
|
||||
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
||||
dir.removeRecursively();
|
||||
|
||||
clearServiceLogs();
|
||||
}
|
||||
|
||||
@@ -7,15 +7,37 @@
|
||||
#include <QString>
|
||||
#include <QTextStream>
|
||||
|
||||
class Debug
|
||||
#include "ui/property_helper.h"
|
||||
|
||||
class Debug : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
AUTO_PROPERTY(QString, sshLog)
|
||||
AUTO_PROPERTY(QString, allLog)
|
||||
|
||||
public:
|
||||
static Debug& Instance();
|
||||
|
||||
static void appendSshLog(const QString &log);
|
||||
static void appendAllLog(const QString &log);
|
||||
|
||||
|
||||
static bool init();
|
||||
static bool openLogsFolder();
|
||||
static bool openServiceLogsFolder();
|
||||
static QString appLogFileNamePath();
|
||||
static void clearLogs();
|
||||
static void clearServiceLogs();
|
||||
static void cleanUp();
|
||||
|
||||
static QString userLogsFilePath();
|
||||
static QString getLogFile();
|
||||
|
||||
private:
|
||||
Debug() {}
|
||||
Debug(Debug const &) = delete;
|
||||
Debug& operator= (Debug const&) = delete;
|
||||
|
||||
static QString userLogsDir();
|
||||
|
||||
static QFile m_file;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#define APPLICATION_NAME "AmneziaVPN"
|
||||
#define SERVICE_NAME "AmneziaVPN-service"
|
||||
#define ORGANIZATION_NAME "AmneziaVPN.ORG"
|
||||
#define APP_MAJOR_VERSION "2.0.1"
|
||||
#define APP_VERSION "2.0.1.0"
|
||||
#define APP_MAJOR_VERSION "2.0.10"
|
||||
#define APP_VERSION "2.0.10.0"
|
||||
|
||||
#endif // DEFINES_H
|
||||
|
||||
BIN
client/images/ios/icon_1024x1024.png
Normal file
|
After Width: | Height: | Size: 499 KiB |
BIN
client/images/ios/icon_120x120.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
client/images/ios/icon_180x180.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
client/images/ios/icon_40x40.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
client/images/ios/icon_58x58.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
client/images/ios/icon_60x60.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
client/images/ios/icon_80x80.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
client/images/ios/icon_87x87.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 324 B |
|
Before Width: | Height: | Size: 690 B |
|
Before Width: | Height: | Size: 454 B |
1
client/images/svg/close_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>
|
||||
|
After Width: | Height: | Size: 268 B |
1
client/images/svg/control_point_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.49 2 2 6.49 2 12s4.49 10 10 10 10-4.49 10-10S17.51 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></svg>
|
||||
|
After Width: | Height: | Size: 317 B |
1
client/images/svg/delete_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z"/></svg>
|
||||
|
After Width: | Height: | Size: 252 B |
1
client/images/svg/density_small_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><g><rect height="2" width="18" x="3" y="2"/><rect height="2" width="18" x="3" y="20"/><rect height="2" width="18" x="3" y="14"/><rect height="2" width="18" x="3" y="8"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 371 B |
1
client/images/svg/done_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></svg>
|
||||
|
After Width: | Height: | Size: 209 B |
1
client/images/svg/format_list_bulleted_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z"/></svg>
|
||||
|
After Width: | Height: | Size: 430 B |
1
client/images/svg/gpp_good_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><path d="M0,0h24v24H0V0z" fill="none"/></g><g><path d="M12,2L4,5v6.09c0,5.05,3.41,9.76,8,10.91c4.59-1.15,8-5.86,8-10.91V5L12,2z M18,11.09c0,4-2.55,7.7-6,8.83 c-3.45-1.13-6-4.82-6-8.83V6.31l6-2.12l6,2.12V11.09z M8.82,10.59L7.4,12l3.54,3.54l5.66-5.66l-1.41-1.41l-4.24,4.24L8.82,10.59z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 434 B |
1
client/images/svg/gpp_maybe_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><path d="M0,0h24v24H0V0z" fill="none"/></g><g><g><path d="M12,2L4,5v6.09c0,5.05,3.41,9.76,8,10.91c4.59-1.15,8-5.86,8-10.91V5L12,2z M18,11.09c0,4-2.55,7.7-6,8.83 c-3.45-1.13-6-4.82-6-8.83v-4.7l6-2.25l6,2.25V11.09z"/><rect height="2" width="2" x="11" y="14"/><rect height="5" width="2" x="11" y="7"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 451 B |
1
client/images/svg/logout_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><path d="M0,0h24v24H0V0z" fill="none"/></g><g><path d="M17,8l-1.41,1.41L17.17,11H9v2h8.17l-1.58,1.58L17,16l4-4L17,8z M5,5h7V3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h7v-2H5V5z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 324 B |
1
client/images/svg/miscellaneous_services_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><g><path d="M14.17,13.71l1.4-2.42c0.09-0.15,0.05-0.34-0.08-0.45l-1.48-1.16c0.03-0.22,0.05-0.45,0.05-0.68s-0.02-0.46-0.05-0.69 l1.48-1.16c0.13-0.11,0.17-0.3,0.08-0.45l-1.4-2.42c-0.09-0.15-0.27-0.21-0.43-0.15L12,4.83c-0.36-0.28-0.75-0.51-1.18-0.69 l-0.26-1.85C10.53,2.13,10.38,2,10.21,2h-2.8C7.24,2,7.09,2.13,7.06,2.3L6.8,4.15C6.38,4.33,5.98,4.56,5.62,4.84l-1.74-0.7 c-0.16-0.06-0.34,0-0.43,0.15l-1.4,2.42C1.96,6.86,2,7.05,2.13,7.16l1.48,1.16C3.58,8.54,3.56,8.77,3.56,9s0.02,0.46,0.05,0.69 l-1.48,1.16C2,10.96,1.96,11.15,2.05,11.3l1.4,2.42c0.09,0.15,0.27,0.21,0.43,0.15l1.74-0.7c0.36,0.28,0.75,0.51,1.18,0.69 l0.26,1.85C7.09,15.87,7.24,16,7.41,16h2.8c0.17,0,0.32-0.13,0.35-0.3l0.26-1.85c0.42-0.18,0.82-0.41,1.18-0.69l1.74,0.7 C13.9,13.92,14.08,13.86,14.17,13.71z M8.81,11c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2s2,0.9,2,2C10.81,10.1,9.91,11,8.81,11z"/><path d="M21.92,18.67l-0.96-0.74c0.02-0.14,0.04-0.29,0.04-0.44c0-0.15-0.01-0.3-0.04-0.44l0.95-0.74 c0.08-0.07,0.11-0.19,0.05-0.29l-0.9-1.55c-0.05-0.1-0.17-0.13-0.28-0.1l-1.11,0.45c-0.23-0.18-0.48-0.33-0.76-0.44l-0.17-1.18 C18.73,13.08,18.63,13,18.53,13h-1.79c-0.11,0-0.21,0.08-0.22,0.19l-0.17,1.18c-0.27,0.12-0.53,0.26-0.76,0.44l-1.11-0.45 c-0.1-0.04-0.22,0-0.28,0.1l-0.9,1.55c-0.05,0.1-0.04,0.22,0.05,0.29l0.95,0.74c-0.02,0.14-0.03,0.29-0.03,0.44 c0,0.15,0.01,0.3,0.03,0.44l-0.95,0.74c-0.08,0.07-0.11,0.19-0.05,0.29l0.9,1.55c0.05,0.1,0.17,0.13,0.28,0.1l1.11-0.45 c0.23,0.18,0.48,0.33,0.76,0.44l0.17,1.18c0.02,0.11,0.11,0.19,0.22,0.19h1.79c0.11,0,0.21-0.08,0.22-0.19l0.17-1.18 c0.27-0.12,0.53-0.26,0.75-0.44l1.12,0.45c0.1,0.04,0.22,0,0.28-0.1l0.9-1.55C22.03,18.86,22,18.74,21.92,18.67z M17.63,18.83 c-0.74,0-1.35-0.6-1.35-1.35s0.6-1.35,1.35-1.35s1.35,0.6,1.35,1.35S18.37,18.83,17.63,18.83z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
1
client/images/svg/refresh_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/></svg>
|
||||
|
After Width: | Height: | Size: 361 B |
1
client/images/svg/settings_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19.43 12.98c.04-.32.07-.64.07-.98 0-.34-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.09-.16-.26-.25-.44-.25-.06 0-.12.01-.17.03l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.06-.02-.12-.03-.18-.03-.17 0-.34.09-.43.25l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98 0 .33.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.09.16.26.25.44.25.06 0 .12-.01.17-.03l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.06.02.12.03.18.03.17 0 .34-.09.43-.25l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zm-1.98-1.71c.04.31.05.52.05.73 0 .21-.02.43-.05.73l-.14 1.13.89.7 1.08.84-.7 1.21-1.27-.51-1.04-.42-.9.68c-.43.32-.84.56-1.25.73l-1.06.43-.16 1.13-.2 1.35h-1.4l-.19-1.35-.16-1.13-1.06-.43c-.43-.18-.83-.41-1.23-.71l-.91-.7-1.06.43-1.27.51-.7-1.21 1.08-.84.89-.7-.14-1.13c-.03-.31-.05-.54-.05-.74s.02-.43.05-.73l.14-1.13-.89-.7-1.08-.84.7-1.21 1.27.51 1.04.42.9-.68c.43-.32.84-.56 1.25-.73l1.06-.43.16-1.13.2-1.35h1.39l.19 1.35.16 1.13 1.06.43c.43.18.83.41 1.23.71l.91.7 1.06-.43 1.27-.51.7 1.21-1.07.85-.89.7.14 1.13zM12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
1
client/images/svg/settings_suggest_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><rect fill="none" height="24" width="24"/><path d="M10,13c0.55,0,1,0.45,1,1s-0.45,1-1,1s-1-0.45-1-1S9.45,13,10,13 M10,11c-1.66,0-3,1.34-3,3s1.34,3,3,3s3-1.34,3-3 S11.66,11,10,11L10,11z M18.5,9l1.09-2.41L22,5.5l-2.41-1.09L18.5,2l-1.09,2.41L15,5.5l2.41,1.09L18.5,9z M21.28,12.72L20.5,11 l-0.78,1.72L18,13.5l1.72,0.78L20.5,16l0.78-1.72L23,13.5L21.28,12.72z M16.25,14c0-0.12,0-0.25-0.01-0.37l1.94-1.47l-2.5-4.33 l-2.24,0.94c-0.2-0.13-0.42-0.26-0.64-0.37L12.5,6h-5L7.2,8.41C6.98,8.52,6.77,8.65,6.56,8.78L4.32,7.83l-2.5,4.33l1.94,1.47 C3.75,13.75,3.75,13.88,3.75,14s0,0.25,0.01,0.37l-1.94,1.47l2.5,4.33l2.24-0.94c0.2,0.13,0.42,0.26,0.64,0.37L7.5,22h5l0.3-2.41 c0.22-0.11,0.43-0.23,0.64-0.37l2.24,0.94l2.5-4.33l-1.94-1.47C16.25,14.25,16.25,14.12,16.25,14z M14.83,17.64l-1.73-0.73 c-0.56,0.6-1.3,1.04-2.13,1.23L10.73,20H9.27l-0.23-1.86c-0.83-0.19-1.57-0.63-2.13-1.23l-1.73,0.73l-0.73-1.27l1.49-1.13 c-0.12-0.39-0.18-0.8-0.18-1.23c0-0.43,0.06-0.84,0.18-1.23l-1.49-1.13l0.73-1.27l1.73,0.73c0.56-0.6,1.3-1.04,2.13-1.23L9.27,8 h1.47l0.23,1.86c0.83,0.19,1.57,0.63,2.13,1.23l1.73-0.73l0.73,1.27l-1.49,1.13c0.12,0.39,0.18,0.8,0.18,1.23 c0,0.43-0.06,0.84-0.18,1.23l1.49,1.13L14.83,17.64z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
client/images/svg/share_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92c0-1.61-1.31-2.92-2.92-2.92zM18 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM6 13c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm12 7.02c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"/></svg>
|
||||
|
After Width: | Height: | Size: 679 B |
1
client/images/svg/vpn_key_black_24dp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M22 19h-6v-4h-2.68c-1.14 2.42-3.6 4-6.32 4-3.86 0-7-3.14-7-7s3.14-7 7-7c2.72 0 5.17 1.58 6.32 4H24v6h-2v4zm-4-2h2v-4h2v-2H11.94l-.23-.67C11.01 8.34 9.11 7 7 7c-2.76 0-5 2.24-5 5s2.24 5 5 5c2.11 0 4.01-1.34 4.71-3.33l.23-.67H18v4zM7 15c-1.65 0-3-1.35-3-3s1.35-3 3-3 3 1.35 3 3-1.35 3-3 3zm0-4c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1z"/></svg>
|
||||
|
After Width: | Height: | Size: 498 B |
62
client/ios/Media.xcassets/AppIcon.appiconset/Contents.json
Normal file
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "icon_40x40.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_60x60.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_58x58.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_87x87.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_80x80.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_120x120.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_120x120-1.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_180x180.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_1024x1024.png",
|
||||
"idiom" : "ios-marketing",
|
||||
"scale" : "1x",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
client/ios/Media.xcassets/AppIcon.appiconset/icon_1024x1024.png
Normal file
|
After Width: | Height: | Size: 499 KiB |
BIN
client/ios/Media.xcassets/AppIcon.appiconset/icon_120x120-1.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
client/ios/Media.xcassets/AppIcon.appiconset/icon_120x120.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
client/ios/Media.xcassets/AppIcon.appiconset/icon_180x180.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
client/ios/Media.xcassets/AppIcon.appiconset/icon_40x40.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
client/ios/Media.xcassets/AppIcon.appiconset/icon_58x58.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
client/ios/Media.xcassets/AppIcon.appiconset/icon_60x60.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
client/ios/Media.xcassets/AppIcon.appiconset/icon_80x80.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
client/ios/Media.xcassets/AppIcon.appiconset/icon_87x87.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
6
client/ios/Media.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,9 @@
|
||||
#include "ui/pages_logic/AppSettingsLogic.h"
|
||||
#include "ui/pages_logic/GeneralSettingsLogic.h"
|
||||
#include "ui/pages_logic/NetworkSettingsLogic.h"
|
||||
#include "ui/pages_logic/ServerConfiguringProgressLogic.h"
|
||||
#include "ui/pages_logic/NewServerProtocolsLogic.h"
|
||||
#include "ui/pages_logic/QrDecoderLogic.h"
|
||||
#include "ui/pages_logic/ServerConfiguringProgressLogic.h"
|
||||
#include "ui/pages_logic/ServerContainersLogic.h"
|
||||
#include "ui/pages_logic/ServerListLogic.h"
|
||||
#include "ui/pages_logic/ServerSettingsLogic.h"
|
||||
@@ -34,6 +35,8 @@
|
||||
|
||||
#include "ui/uilogic.h"
|
||||
|
||||
#include "QZXing.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "defines.h"
|
||||
|
||||
@@ -48,6 +51,10 @@
|
||||
#include "Windows.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#include "native.h"
|
||||
#endif
|
||||
|
||||
static void loadTranslator()
|
||||
{
|
||||
QTranslator* translator = new QTranslator;
|
||||
@@ -79,10 +86,15 @@ int main(int argc, char *argv[])
|
||||
QApplication app(argc, argv);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
AllowSetForegroundWindow(0);
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
NativeHelpers::registerApplicationInstance(&app);
|
||||
#endif
|
||||
|
||||
loadTranslator();
|
||||
|
||||
QFontDatabase::addApplicationFont(":/fonts/Lato-Black.ttf");
|
||||
@@ -108,14 +120,32 @@ int main(int argc, char *argv[])
|
||||
QCommandLineOption c_autostart {{"a", "autostart"}, "System autostart"};
|
||||
parser.addOption(c_autostart);
|
||||
|
||||
QCommandLineOption c_cleanup {{"c", "cleanup"}, "Cleanup logs"};
|
||||
parser.addOption(c_cleanup);
|
||||
|
||||
parser.process(app);
|
||||
|
||||
if (!Debug::init()) {
|
||||
qWarning() << "Initialization of debug subsystem failed";
|
||||
if (parser.isSet(c_cleanup)) {
|
||||
Debug::cleanUp();
|
||||
QTimer::singleShot(100,[&app]{
|
||||
app.quit();
|
||||
});
|
||||
app.exec();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Settings settings;
|
||||
|
||||
if (settings.isSaveLogs()) {
|
||||
if (!Debug::init()) {
|
||||
qWarning() << "Initialization of debug subsystem failed";
|
||||
}
|
||||
}
|
||||
|
||||
app.setQuitOnLastWindowClosed(false);
|
||||
|
||||
QZXing::registerQMLTypes();
|
||||
|
||||
qRegisterMetaType<VpnProtocol::VpnConnectionState>("VpnProtocol::VpnConnectionState");
|
||||
qRegisterMetaType<ServerCredentials>("ServerCredentials");
|
||||
|
||||
@@ -151,13 +181,16 @@ int main(int argc, char *argv[])
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
engine->rootContext()->setContextProperty("Debug", &Debug::Instance());
|
||||
|
||||
engine->rootContext()->setContextProperty("UiLogic", uiLogic);
|
||||
|
||||
engine->rootContext()->setContextProperty("AppSettingsLogic", uiLogic->appSettingsLogic());
|
||||
engine->rootContext()->setContextProperty("GeneralSettingsLogic", uiLogic->generalSettingsLogic());
|
||||
engine->rootContext()->setContextProperty("NetworkSettingsLogic", uiLogic->networkSettingsLogic());
|
||||
engine->rootContext()->setContextProperty("ServerConfiguringProgressLogic", uiLogic->serverConfiguringProgressLogic());
|
||||
engine->rootContext()->setContextProperty("NewServerProtocolsLogic", uiLogic->newServerProtocolsLogic());
|
||||
engine->rootContext()->setContextProperty("QrDecoderLogic", uiLogic->qrDecoderLogic());
|
||||
engine->rootContext()->setContextProperty("ServerConfiguringProgressLogic", uiLogic->serverConfiguringProgressLogic());
|
||||
engine->rootContext()->setContextProperty("ServerListLogic", uiLogic->serverListLogic());
|
||||
engine->rootContext()->setContextProperty("ServerSettingsLogic", uiLogic->serverSettingsLogic());
|
||||
engine->rootContext()->setContextProperty("ServerContainersLogic", uiLogic->serverprotocolsLogic());
|
||||
@@ -181,26 +214,23 @@ int main(int argc, char *argv[])
|
||||
uiLogic->setQmlRoot(engine->rootObjects().at(0));
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (parser.isSet("a")) uiLogic->showOnStartup();
|
||||
else emit uiLogic->show();
|
||||
#else
|
||||
uiLogic->showOnStartup();
|
||||
#endif
|
||||
|
||||
// TODO - fix
|
||||
//#ifdef Q_OS_WIN
|
||||
// if (parser.isSet("a")) mainWindow.showOnStartup();
|
||||
// else mainWindow.show();
|
||||
//#else
|
||||
// mainWindow.showOnStartup();
|
||||
//#endif
|
||||
|
||||
|
||||
// TODO - fix
|
||||
//#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
// if (app.isPrimary()) {
|
||||
// QObject::connect(&app, &SingleApplication::instanceStarted, &mainWindow, [&](){
|
||||
// qDebug() << "Secondary instance started, showing this window instead";
|
||||
// mainWindow.show();
|
||||
// mainWindow.showNormal();
|
||||
// mainWindow.raise();
|
||||
// });
|
||||
// }
|
||||
//#endif
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
if (app.isPrimary()) {
|
||||
QObject::connect(&app, &SingleApplication::instanceStarted, uiLogic, [&](){
|
||||
qDebug() << "Secondary instance started, showing this window instead";
|
||||
emit uiLogic->show();
|
||||
emit uiLogic->raise();
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
54
client/platforms/android/native.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "native.h"
|
||||
#include <QMetaObject>
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#include <jni.h>
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
|
||||
QObject *NativeHelpers::application_p_ = 0;
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
|
||||
// define our native static functions
|
||||
// these are the functions that Java part will call directly from Android UI thread
|
||||
static void onPermissionsGranted(JNIEnv * /*env*/, jobject /*obj*/)
|
||||
{
|
||||
QMetaObject::invokeMethod(NativeHelpers::getApplicationInstance(), "onPermissionsGranted"
|
||||
, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
static void onPermissionsDenied(JNIEnv * /*env*/, jobject /*obj*/)
|
||||
{
|
||||
QMetaObject::invokeMethod(NativeHelpers::getApplicationInstance(), "onPermissionsDenied"
|
||||
, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
//create a vector with all our JNINativeMethod(s)
|
||||
static JNINativeMethod methods[] = {
|
||||
{"onPermissionsGranted", "()V", (void *)onPermissionsGranted},
|
||||
{"onPermissionsDenied", "()V", (void *)onPermissionsDenied},
|
||||
};
|
||||
|
||||
// this method is called automatically by Java after the .so file is loaded
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
|
||||
{
|
||||
JNIEnv* env;
|
||||
// get the JNIEnv pointer.
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
|
||||
return JNI_ERR;
|
||||
|
||||
// search for Java class which declares the native methods
|
||||
jclass javaClass = env->FindClass("org/ftylitak/qzxing/NativeFunctions");
|
||||
if (!javaClass)
|
||||
return JNI_ERR;
|
||||
|
||||
// register our native methods
|
||||
if (env->RegisterNatives(javaClass, methods,
|
||||
sizeof(methods) / sizeof(methods[0])) < 0) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
#endif // Q_OS_ANDROID
|
||||
20
client/platforms/android/native.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef NATIVE_H
|
||||
#define NATIVE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class NativeHelpers {
|
||||
public:
|
||||
static void registerApplicationInstance(QObject *app_p) {
|
||||
application_p_ = app_p;
|
||||
}
|
||||
|
||||
static QObject* getApplicationInstance() {
|
||||
return application_p_;
|
||||
}
|
||||
|
||||
private:
|
||||
static QObject *application_p_;
|
||||
};
|
||||
|
||||
#endif // NATIVE_H
|
||||
@@ -4,94 +4,72 @@
|
||||
import Foundation
|
||||
import NetworkExtension
|
||||
import os
|
||||
import OpenVPNAdapter
|
||||
|
||||
enum TunnelProtoType: String {
|
||||
case wireguard, openvpn, none
|
||||
}
|
||||
|
||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
|
||||
|
||||
private lazy var wgAdapter: WireGuardAdapter = {
|
||||
return WireGuardAdapter(with: self) { logLevel, message in
|
||||
wg_log(logLevel.osLogLevel, message: message)
|
||||
}
|
||||
}()
|
||||
|
||||
private lazy var ovpnAdapter: OpenVPNAdapter = {
|
||||
let adapter = OpenVPNAdapter()
|
||||
adapter.delegate = self
|
||||
return adapter
|
||||
}()
|
||||
|
||||
let vpnReachability = OpenVPNReachability()
|
||||
|
||||
var startHandler: ((Error?) -> Void)?
|
||||
var stopHandler: (() -> Void)?
|
||||
var protoType: TunnelProtoType = .wireguard
|
||||
|
||||
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
||||
let activationAttemptId = options?["activationAttemptId"] as? String
|
||||
let errorNotifier = ErrorNotifier(activationAttemptId: activationAttemptId)
|
||||
|
||||
|
||||
Logger.configureGlobal(tagged: "NET", withFilePath: FileManager.logFileURL?.path)
|
||||
|
||||
wg_log(.info, message: "Starting tunnel from the " + (activationAttemptId == nil ? "OS directly, rather than the app" : "app"))
|
||||
|
||||
guard let tunnelProviderProtocol = self.protocolConfiguration as? NETunnelProviderProtocol,
|
||||
let tunnelConfiguration = tunnelProviderProtocol.asTunnelConfiguration() else {
|
||||
errorNotifier.notify(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid)
|
||||
completionHandler(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid)
|
||||
return
|
||||
|
||||
if let protocolConfiguration = self.protocolConfiguration as? NETunnelProviderProtocol,
|
||||
let providerConfiguration = protocolConfiguration.providerConfiguration,
|
||||
let _: Data = providerConfiguration["ovpn"] as? Data {
|
||||
protoType = .openvpn
|
||||
} else {
|
||||
protoType = .wireguard
|
||||
}
|
||||
|
||||
// Start the tunnel
|
||||
wgAdapter.start(tunnelConfiguration: tunnelConfiguration) { adapterError in
|
||||
guard let adapterError = adapterError else {
|
||||
let interfaceName = self.wgAdapter.interfaceName ?? "unknown"
|
||||
|
||||
wg_log(.info, message: "Tunnel interface is \(interfaceName)")
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
switch protoType {
|
||||
case .wireguard:
|
||||
startWireguard(activationAttemptId: activationAttemptId,
|
||||
errorNotifier: errorNotifier,
|
||||
completionHandler: completionHandler)
|
||||
case .openvpn:
|
||||
startOpenVPN(completionHandler: completionHandler)
|
||||
case .none:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func stopTunnel(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
|
||||
// sufficient quantities of users.
|
||||
exit(0)
|
||||
#endif
|
||||
switch protoType {
|
||||
case .wireguard:
|
||||
stopWireguard(with: reason, completionHandler: completionHandler)
|
||||
case .openvpn:
|
||||
stopOpenVPN(with: reason, completionHandler: completionHandler)
|
||||
case .none:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
|
||||
guard let completionHandler = completionHandler else { return }
|
||||
|
||||
|
||||
if messageData.count == 1 && messageData[0] == 0 {
|
||||
wgAdapter.getRuntimeConfiguration { settings in
|
||||
var data: Data?
|
||||
@@ -108,31 +86,144 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
completionHandler(nil)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
let tunnelConfiguration = try TunnelConfiguration(fromWgQuickConfig: configString)
|
||||
wgAdapter.update(tunnelConfiguration: tunnelConfiguration) { error in
|
||||
if let error = error {
|
||||
wg_log(.error, message: "Failed to switch tunnel configuration: \(error.localizedDescription)")
|
||||
completionHandler(nil)
|
||||
return
|
||||
let tunnelConfiguration = try TunnelConfiguration(fromWgQuickConfig: configString)
|
||||
wgAdapter.update(tunnelConfiguration: tunnelConfiguration) { error in
|
||||
if let error = error {
|
||||
wg_log(.error, message: "Failed to switch tunnel configuration: \(error.localizedDescription)")
|
||||
completionHandler(nil)
|
||||
return
|
||||
}
|
||||
|
||||
self.wgAdapter.getRuntimeConfiguration { settings in
|
||||
var data: Data?
|
||||
if let settings = settings {
|
||||
data = settings.data(using: .utf8)!
|
||||
}
|
||||
completionHandler(data)
|
||||
}
|
||||
}
|
||||
|
||||
self.wgAdapter.getRuntimeConfiguration { settings in
|
||||
var data: Data?
|
||||
if let settings = settings {
|
||||
data = settings.data(using: .utf8)!
|
||||
}
|
||||
completionHandler(data)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
completionHandler(nil)
|
||||
completionHandler(nil)
|
||||
}
|
||||
} else {
|
||||
completionHandler(nil)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Private methods
|
||||
private func startWireguard(activationAttemptId: String?,
|
||||
errorNotifier: ErrorNotifier,
|
||||
completionHandler: @escaping (Error?) -> Void) {
|
||||
guard let tunnelProviderProtocol = self.protocolConfiguration as? NETunnelProviderProtocol,
|
||||
let tunnelConfiguration = tunnelProviderProtocol.asTunnelConfiguration() else {
|
||||
errorNotifier.notify(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid)
|
||||
completionHandler(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid)
|
||||
return
|
||||
}
|
||||
wg_log(.info, message: "Starting wireguard tunnel from the " + (activationAttemptId == nil ? "OS directly, rather than the app" : "app"))
|
||||
|
||||
// Start the tunnel
|
||||
wgAdapter.start(tunnelConfiguration: tunnelConfiguration) { adapterError in
|
||||
guard let adapterError = adapterError else {
|
||||
let interfaceName = self.wgAdapter.interfaceName ?? "unknown"
|
||||
|
||||
wg_log(.info, message: "Tunnel interface is \(interfaceName)")
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func startOpenVPN(completionHandler: @escaping (Error?) -> Void) {
|
||||
guard let protocolConfiguration = self.protocolConfiguration as? NETunnelProviderProtocol,
|
||||
let providerConfiguration = protocolConfiguration.providerConfiguration,
|
||||
let ovpnConfiguration: Data = providerConfiguration["ovpn"] as? Data else {
|
||||
return
|
||||
}
|
||||
|
||||
let configuration = OpenVPNConfiguration()
|
||||
configuration.fileContent = ovpnConfiguration
|
||||
// configuration.settings = [] // Additional setting if needed any
|
||||
// configuration.tunPersist = true // keep tun active during pauses/reconections
|
||||
let evaluation: OpenVPNConfigurationEvaluation
|
||||
do {
|
||||
evaluation = try ovpnAdapter.apply(configuration: configuration)
|
||||
} catch {
|
||||
completionHandler(error)
|
||||
return
|
||||
}
|
||||
|
||||
if !evaluation.autologin {
|
||||
print("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)
|
||||
}
|
||||
|
||||
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
|
||||
// sufficient quantities of users.
|
||||
exit(0)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private func stopOpenVPN(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
|
||||
stopHandler = completionHandler
|
||||
if vpnReachability.isTracking {
|
||||
vpnReachability.stopTracking()
|
||||
}
|
||||
ovpnAdapter.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
extension WireGuardLogLevel {
|
||||
@@ -145,3 +236,87 @@ extension WireGuardLogLevel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NEPacketTunnelFlow: OpenVPNAdapterPacketFlow {}
|
||||
|
||||
extension PacketTunnelProvider: OpenVPNAdapterDelegate {
|
||||
|
||||
// OpenVPNAdapter calls this delegate method to configure a VPN tunnel.
|
||||
// `completionHandler` callback requires an object conforming to `OpenVPNAdapterPacketFlow`
|
||||
// protocol if the tunnel is configured without errors. Otherwise send nil.
|
||||
// `OpenVPNAdapterPacketFlow` method signatures are similar to `NEPacketTunnelFlow` so
|
||||
// you can just extend that class to adopt `OpenVPNAdapterPacketFlow` protocol and
|
||||
// send `self.packetFlow` to `completionHandler` callback.
|
||||
func openVPNAdapter(
|
||||
_ openVPNAdapter: OpenVPNAdapter,
|
||||
configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings?,
|
||||
completionHandler: @escaping (Error?) -> Void
|
||||
) {
|
||||
// In order to direct all DNS queries first to the VPN DNS servers before the primary DNS servers
|
||||
// send empty string to NEDNSSettings.matchDomains
|
||||
networkSettings?.dnsSettings?.matchDomains = [""]
|
||||
|
||||
// Set the network settings for the current tunneling session.
|
||||
setTunnelNetworkSettings(networkSettings, completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
// Process events returned by the OpenVPN library
|
||||
func openVPNAdapter(
|
||||
_ openVPNAdapter: OpenVPNAdapter,
|
||||
handleEvent event:
|
||||
OpenVPNAdapterEvent, message: String?
|
||||
) {
|
||||
switch event {
|
||||
case .connected:
|
||||
if reasserting {
|
||||
reasserting = false
|
||||
}
|
||||
|
||||
guard let startHandler = startHandler else { return }
|
||||
|
||||
startHandler(nil)
|
||||
self.startHandler = nil
|
||||
|
||||
case .disconnected:
|
||||
guard let stopHandler = stopHandler else { return }
|
||||
|
||||
if vpnReachability.isTracking {
|
||||
vpnReachability.stopTracking()
|
||||
}
|
||||
|
||||
stopHandler()
|
||||
self.stopHandler = nil
|
||||
|
||||
case .reconnecting:
|
||||
reasserting = true
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Handle errors thrown by the OpenVPN library
|
||||
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleError error: Error) {
|
||||
// Handle only fatal errors
|
||||
guard let fatal = (error as NSError).userInfo[OpenVPNAdapterErrorFatalKey] as? Bool,
|
||||
fatal == true else { return }
|
||||
|
||||
if vpnReachability.isTracking {
|
||||
vpnReachability.stopTracking()
|
||||
}
|
||||
|
||||
if let startHandler = startHandler {
|
||||
startHandler(error)
|
||||
self.startHandler = nil
|
||||
} else {
|
||||
cancelTunnelWithError(error)
|
||||
}
|
||||
}
|
||||
|
||||
// Use this method to process any log message returned by OpenVPN library.
|
||||
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleLogMessage logMessage: String) {
|
||||
// Handle log messages
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import Foundation
|
||||
import NetworkExtension
|
||||
|
||||
let vpnName = "AmneziaVPN"
|
||||
let vpnName = "Amnezia WireguardVPN"
|
||||
var vpnBundleID = "";
|
||||
|
||||
@objc class VPNIPAddressRange : NSObject {
|
||||
@@ -30,27 +30,32 @@ public class IOSVpnProtocolImpl : NSObject {
|
||||
private var deviceIpv4Address: String? = nil
|
||||
private var deviceIpv6Address: String? = nil
|
||||
|
||||
@objc enum IOSConnectionState: Int { case Error, Connected, Disconnected }
|
||||
|
||||
@objc init(bundleID: String, privateKey: Data, deviceIpv4Address: String, deviceIpv6Address: String, closure: @escaping (IOSConnectionState, Date?) -> Void, callback: @escaping (Bool) -> Void) {
|
||||
@objc enum ConnectionState: Int { case Error, Connected, Disconnected }
|
||||
|
||||
@objc init(bundleID: String,
|
||||
config: String,
|
||||
closure: @escaping (ConnectionState, Date?) -> Void,
|
||||
callback: @escaping (Bool) -> Void) {
|
||||
super.init()
|
||||
|
||||
Logger.configureGlobal(tagged: "APP", withFilePath: "")
|
||||
|
||||
print("Config from caller: \(config)")
|
||||
|
||||
vpnBundleID = bundleID;
|
||||
precondition(!vpnBundleID.isEmpty)
|
||||
|
||||
|
||||
stateChangeCallback = callback
|
||||
self.privateKey = PrivateKey(rawValue: privateKey)
|
||||
self.deviceIpv4Address = deviceIpv4Address
|
||||
self.deviceIpv6Address = deviceIpv6Address
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(self.vpnStatusDidChange(notification:)), name: Notification.Name.NEVPNStatusDidChange, object: nil)
|
||||
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(self.vpnStatusDidChange(notification:)),
|
||||
name: Notification.Name.NEVPNStatusDidChange,
|
||||
object: nil)
|
||||
|
||||
NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in
|
||||
if let error = error {
|
||||
Logger.global?.log(message: "Loading from preference failed: \(error)")
|
||||
closure(IOSConnectionState.Error, nil)
|
||||
closure(ConnectionState.Error, nil)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -64,11 +69,22 @@ public class IOSVpnProtocolImpl : NSObject {
|
||||
print("We have received \(nsManagers.count) managers.")
|
||||
|
||||
let tunnel = nsManagers.first(where: IOSVpnProtocolImpl.isOurManager(_:))
|
||||
|
||||
// if let name = tunnel?.localizedDescription, name == vpnName {
|
||||
// tunnel?.removeFromPreferences(completionHandler: { removeError in
|
||||
// if let error = removeError {
|
||||
// Logger.global?.log(message: "WireguardVPN Tunnel Remove from Prefs Error: \(error)")
|
||||
// closure(ConnectionState.Error, nil)
|
||||
// return
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
if tunnel == nil {
|
||||
Logger.global?.log(message: "Creating the tunnel")
|
||||
print("Creating the tunnel")
|
||||
self!.tunnel = NETunnelProviderManager()
|
||||
closure(IOSConnectionState.Disconnected, nil)
|
||||
closure(ConnectionState.Disconnected, nil)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -77,9 +93,80 @@ public class IOSVpnProtocolImpl : NSObject {
|
||||
|
||||
self!.tunnel = tunnel
|
||||
if tunnel?.connection.status == .connected {
|
||||
closure(IOSConnectionState.Connected, tunnel?.connection.connectedDate)
|
||||
closure(ConnectionState.Connected, tunnel?.connection.connectedDate)
|
||||
} else {
|
||||
closure(IOSConnectionState.Disconnected, nil)
|
||||
closure(ConnectionState.Disconnected, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc init(bundleID: String,
|
||||
privateKey: Data,
|
||||
deviceIpv4Address: String,
|
||||
deviceIpv6Address: String,
|
||||
closure: @escaping (ConnectionState, Date?) -> Void,
|
||||
callback: @escaping (Bool) -> Void) {
|
||||
super.init()
|
||||
|
||||
Logger.configureGlobal(tagged: "APP", withFilePath: "")
|
||||
|
||||
vpnBundleID = bundleID;
|
||||
precondition(!vpnBundleID.isEmpty)
|
||||
|
||||
stateChangeCallback = callback
|
||||
self.privateKey = PrivateKey(rawValue: privateKey)
|
||||
self.deviceIpv4Address = deviceIpv4Address
|
||||
self.deviceIpv6Address = deviceIpv6Address
|
||||
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(self.vpnStatusDidChange(notification:)), name: Notification.Name.NEVPNStatusDidChange, object: nil)
|
||||
|
||||
NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in
|
||||
if let error = error {
|
||||
Logger.global?.log(message: "Loading from preference failed: \(error)")
|
||||
closure(ConnectionState.Error, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if self == nil {
|
||||
Logger.global?.log(message: "We are shutting down.")
|
||||
return
|
||||
}
|
||||
|
||||
let nsManagers = managers ?? []
|
||||
Logger.global?.log(message: "We have received \(nsManagers.count) managers.")
|
||||
print("We have received \(nsManagers.count) managers.")
|
||||
|
||||
let tunnel = nsManagers.first(where: IOSVpnProtocolImpl.isOurManager(_:))
|
||||
|
||||
// if let name = tunnel?.localizedDescription, name != vpnName {
|
||||
// tunnel?.removeFromPreferences(completionHandler: { removeError in
|
||||
// if let error = removeError {
|
||||
// Logger.global?.log(message: "OpenVpn Tunnel Remove from Prefs Error: \(error)")
|
||||
// closure(ConnectionState.Error, nil)
|
||||
// return
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
if tunnel == nil {
|
||||
Logger.global?.log(message: "Creating the tunnel")
|
||||
print("Creating the tunnel")
|
||||
self!.tunnel = NETunnelProviderManager()
|
||||
closure(ConnectionState.Disconnected, nil)
|
||||
return
|
||||
}
|
||||
|
||||
Logger.global?.log(message: "Tunnel already exists")
|
||||
print("Tunnel already exists")
|
||||
|
||||
self!.tunnel = tunnel
|
||||
|
||||
if tunnel?.connection.status == .connected {
|
||||
closure(ConnectionState.Connected, tunnel?.connection.connectedDate)
|
||||
} else {
|
||||
closure(ConnectionState.Disconnected, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,6 +229,22 @@ public class IOSVpnProtocolImpl : NSObject {
|
||||
print("Found the manager with the correct bundle identifier: \(tunnelProto.providerBundleIdentifier!)")
|
||||
return true
|
||||
}
|
||||
|
||||
@objc func connect(ovpnConfig: String, failureCallback: @escaping () -> Void) {
|
||||
Logger.global?.log(message: "Connecting")
|
||||
assert(tunnel != nil)
|
||||
|
||||
let addr: String = ovpnConfig
|
||||
.splitToArray(separator: "\n", trimmingCharacters: nil)
|
||||
.first { $0.starts(with: "remote ") }
|
||||
.splitToArray(separator: " ", trimmingCharacters: nil)[1]
|
||||
print("server: \(addr)")
|
||||
|
||||
// Let's remove the previous config if it exists.
|
||||
(tunnel?.protocolConfiguration as? NETunnelProviderProtocol)?.destroyConfigurationReference()
|
||||
|
||||
self.configureOpenVPNTunnel(serverAddress: addr, config: ovpnConfig, failureCallback: failureCallback)
|
||||
}
|
||||
|
||||
@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")
|
||||
@@ -247,6 +350,46 @@ public class IOSVpnProtocolImpl : NSObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func configureOpenVPNTunnel(serverAddress: String, config: String, failureCallback: @escaping () -> Void) {
|
||||
let tunnelProtocol = NETunnelProviderProtocol()
|
||||
tunnelProtocol.serverAddress = serverAddress
|
||||
tunnelProtocol.providerBundleIdentifier = vpnBundleID
|
||||
tunnelProtocol.providerConfiguration = ["ovpn": Data(config.utf8)]
|
||||
tunnel?.protocolConfiguration = tunnelProtocol
|
||||
tunnel?.localizedDescription = "Amnezia OpenVPN"
|
||||
tunnel?.isEnabled = true
|
||||
|
||||
tunnel?.saveToPreferences { [unowned self] saveError in
|
||||
if let error = saveError {
|
||||
Logger.global?.log(message: "Connect OpenVPN Tunnel Save Error: \(error)")
|
||||
failureCallback()
|
||||
return
|
||||
}
|
||||
|
||||
Logger.global?.log(message: "Saving the OpenVPN tunnel succeeded")
|
||||
|
||||
self.tunnel?.loadFromPreferences { error in
|
||||
if let error = error {
|
||||
Logger.global?.log(message: "Connect OpenVPN Tunnel Load Error: \(error)")
|
||||
failureCallback()
|
||||
return
|
||||
}
|
||||
|
||||
Logger.global?.log(message: "Loading the OpenVPN tunnel succeeded")
|
||||
print("Loading the openvpn tunnel succeeded")
|
||||
|
||||
do {
|
||||
print("starting openvpn tunnel")
|
||||
try self.tunnel?.connection.startVPNTunnel()
|
||||
} catch let error {
|
||||
Logger.global?.log(message: "Something went wrong: \(error)")
|
||||
failureCallback()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func disconnect() {
|
||||
Logger.global?.log(message: "Disconnecting")
|
||||
@@ -257,7 +400,74 @@ public class IOSVpnProtocolImpl : NSObject {
|
||||
@objc func checkStatus(callback: @escaping (String, String, String) -> Void) {
|
||||
Logger.global?.log(message: "Check status")
|
||||
assert(tunnel != nil)
|
||||
|
||||
let protoType = (tunnel!.localizedDescription ?? "").toTunnelType
|
||||
|
||||
switch protoType {
|
||||
case .wireguard:
|
||||
checkWireguardStatus(callback: callback)
|
||||
case .openvpn:
|
||||
checkOVPNStatus(callback: callback)
|
||||
case .empty:
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
guard let configData = proto.providerConfiguration?["ovpn"] as? Data,
|
||||
let ovpnConfig = String(data: configData, encoding: .utf8) else {
|
||||
callback("", "", "")
|
||||
return
|
||||
}
|
||||
|
||||
let serverIpv4Gateway: String = ovpnConfig
|
||||
.splitToArray(separator: "\n", trimmingCharacters: nil)
|
||||
.first { $0.starts(with: "remote ") }
|
||||
.splitToArray(separator: " ", trimmingCharacters: nil)[1]
|
||||
|
||||
print("server IP: \(serverIpv4Gateway)")
|
||||
|
||||
|
||||
let deviceIpv4Address = getTunIPAddress()
|
||||
print("device IP: \(serverIpv4Gateway)")
|
||||
if deviceIpv4Address == nil {
|
||||
callback("", "", "")
|
||||
return
|
||||
}
|
||||
|
||||
guard let session = tunnel?.connection as? NETunnelProviderSession else {
|
||||
callback("", "", "")
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
try session.sendProviderMessage(Data([UInt8(0)])) { [callback] data in
|
||||
guard let data = data,
|
||||
let configString = String(data: data, encoding: .utf8)
|
||||
else {
|
||||
Logger.global?.log(message: "Failed to convert data to string")
|
||||
callback("", "", "")
|
||||
return
|
||||
}
|
||||
|
||||
callback("\(serverIpv4Gateway)", "\(deviceIpv4Address!)", configString)
|
||||
}
|
||||
} catch {
|
||||
Logger.global?.log(message: "Failed to retrieve data from session")
|
||||
callback("", "", "")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func checkWireguardStatus(callback: @escaping (String, String, String) -> Void) {
|
||||
Logger.global?.log(message: "Check Wireguard")
|
||||
let proto = tunnel!.protocolConfiguration as? NETunnelProviderProtocol
|
||||
if proto == nil {
|
||||
callback("", "", "")
|
||||
@@ -305,4 +515,50 @@ public class IOSVpnProtocolImpl : NSObject {
|
||||
callback("", "", "")
|
||||
}
|
||||
}
|
||||
|
||||
private func getTunIPAddress() -> String? {
|
||||
var address: String? = nil
|
||||
var interfaces: UnsafeMutablePointer<ifaddrs>? = nil
|
||||
var temp_addr: UnsafeMutablePointer<ifaddrs>? = nil
|
||||
var success: Int = 0
|
||||
|
||||
// retrieve the current interfaces - returns 0 on success
|
||||
success = Int(getifaddrs(&interfaces))
|
||||
if success == 0 {
|
||||
// Loop through linked list of interfaces
|
||||
temp_addr = interfaces
|
||||
while temp_addr != nil {
|
||||
if temp_addr?.pointee.ifa_addr == nil {
|
||||
continue
|
||||
}
|
||||
if temp_addr?.pointee.ifa_addr.pointee.sa_family == UInt8(AF_INET) {
|
||||
// Check if interface is en0 which is the wifi connection on the iPhone
|
||||
if let name = temp_addr?.pointee.ifa_name, ((String(utf8String: name)?.contains("tun")) != nil) {
|
||||
// Get NSString from C String
|
||||
if let value = temp_addr?.pointee.ifa_addr as? sockaddr_in {
|
||||
address = String(utf8String: inet_ntoa(value.sin_addr))
|
||||
}
|
||||
}
|
||||
}
|
||||
temp_addr = temp_addr?.pointee.ifa_next
|
||||
}
|
||||
}
|
||||
freeifaddrs(interfaces)
|
||||
return address
|
||||
}
|
||||
}
|
||||
|
||||
enum TunnelType: String {
|
||||
case wireguard, openvpn, empty
|
||||
}
|
||||
|
||||
extension String {
|
||||
var toTunnelType: TunnelType {
|
||||
switch self {
|
||||
case "wireguard": return .wireguard
|
||||
case "openvpn": return .openvpn
|
||||
default:
|
||||
return .empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,41 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
|
||||
#include <QThread>
|
||||
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ikev2_vpn_protocol.h"
|
||||
#include "ikev2_vpn_protocol_windows.h"
|
||||
#include "utils.h"
|
||||
|
||||
static Ikev2Protocol* self = nullptr;
|
||||
static std::mutex rasDialFuncMutex;
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
extern "C" {
|
||||
static void WINAPI RasDialFuncCallback(UINT unMsg,
|
||||
RASCONNSTATE rasconnstate,
|
||||
DWORD dwError );
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) :
|
||||
VpnProtocol(configuration, parent)
|
||||
{
|
||||
self = this;
|
||||
//m_configFile.setFileTemplate(QDir::tempPath() + QDir::separator() + serviceName() + ".conf");
|
||||
readIkev2Configuration(configuration);
|
||||
}
|
||||
|
||||
Ikev2Protocol::~Ikev2Protocol()
|
||||
{
|
||||
qDebug() << "IpsecProtocol::~IpsecProtocol()";
|
||||
#ifdef Q_OS_WIN
|
||||
disconnect_vpn();
|
||||
#endif
|
||||
Ikev2Protocol::stop();
|
||||
}
|
||||
|
||||
void Ikev2Protocol::stop()
|
||||
{
|
||||
setConnectionState(VpnProtocol::Disconnecting);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
{
|
||||
if (! disconnect_vpn() ){
|
||||
qDebug()<<"We don't disconnect";
|
||||
@@ -51,7 +45,6 @@ void Ikev2Protocol::stop()
|
||||
setConnectionState(VpnProtocol::Disconnected);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Ikev2Protocol::newConnectionStateEventReceived(UINT unMsg, tagRASCONNSTATE rasconnstate, DWORD dwError)
|
||||
@@ -61,40 +54,40 @@ void Ikev2Protocol::newConnectionStateEventReceived(UINT unMsg, tagRASCONNSTATE
|
||||
switch (rasconnstate)
|
||||
{
|
||||
case RASCS_OpenPort:
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
setConnectionState(Preparing);
|
||||
break;
|
||||
case RASCS_PortOpened:
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
setConnectionState(Preparing);
|
||||
break;
|
||||
case RASCS_ConnectDevice:
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
setConnectionState(Preparing);
|
||||
break;
|
||||
case RASCS_DeviceConnected:
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
setConnectionState(Preparing);
|
||||
break;
|
||||
case RASCS_AllDevicesConnected:
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
setConnectionState(Preparing);
|
||||
break;
|
||||
case RASCS_Authenticate:
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
setConnectionState(Preparing);
|
||||
break;
|
||||
case RASCS_AuthNotify:
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
if (dwError != 0) {
|
||||
qDebug() << "have error" << dwError;
|
||||
//qDebug() << "have error" << dwError;
|
||||
setConnectionState(Disconnected);
|
||||
} else {
|
||||
qDebug() << "RASCS_AuthNotify but no error" << dwError;
|
||||
//qDebug() << "RASCS_AuthNotify but no error" << dwError;
|
||||
}
|
||||
break;
|
||||
case RASCS_AuthRetry:
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
setConnectionState(Preparing);
|
||||
break;
|
||||
case RASCS_AuthCallback:
|
||||
@@ -113,10 +106,10 @@ void Ikev2Protocol::newConnectionStateEventReceived(UINT unMsg, tagRASCONNSTATE
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
break;
|
||||
case RASCS_ReAuthenticate:
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
break;
|
||||
case RASCS_Authenticated:
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
break;
|
||||
case RASCS_PrepareForCallback:
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
@@ -164,51 +157,14 @@ void Ikev2Protocol::newConnectionStateEventReceived(UINT unMsg, tagRASCONNSTATE
|
||||
|
||||
case RASCS_Connected: // = RASCS_DONE:
|
||||
setConnectionState(Connected);
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//printf ("RASCS_Connected = %d\n", _connection_state);
|
||||
//printf ("Connection completed.\n");
|
||||
//SetEvent(gEvent_handle);
|
||||
{
|
||||
//get the network settings of adapters
|
||||
std::this_thread::sleep_for(std::chrono::seconds(4));
|
||||
std::string p1,p2,p3;
|
||||
const auto ret = adpInfo.get_adapter_info(tunnelName().toStdString());
|
||||
if (std::get<0>(ret) == false){
|
||||
p1 = adpInfo.get_adapter_route_gateway();
|
||||
p2 = adpInfo.get_adapter_local_address();
|
||||
p3 = adpInfo.get_adapter_local_gateway();
|
||||
m_routeGateway = QString::fromStdString(p1);
|
||||
m_vpnLocalAddress = QString::fromStdString(p2);
|
||||
m_vpnGateway = QString::fromStdString(p3);
|
||||
qDebug()<<"My ikev2 m_routeGateway "<<m_routeGateway;
|
||||
qDebug()<<"My ikev2 m_vpnLocalAddress "<<m_vpnLocalAddress;
|
||||
qDebug()<<"My ikev2 m_vpnGateway "<< m_vpnGateway;
|
||||
auto ret = adpinfo::get_route_table(p2.c_str());
|
||||
{
|
||||
for (const auto &itret: ret){
|
||||
const auto ip = itret.szDestIp;//std::get<0>(itret);
|
||||
const auto msk = itret.szMaskIp;//std::get<1>(itret);
|
||||
const auto gw = itret.szGatewayIp;//std::get<2>(itret);
|
||||
const auto itf = itret.szInterfaceIp;//std::get<3>(itret);
|
||||
const auto itfInd = itret.ulIfIndex;
|
||||
qDebug()<<"IP["<<ip.c_str()<<"]"<<"Mask["<<msk.c_str()<<"]"<<"gateway["<<gw.c_str()<<"]"<<"Interface["<<itf.c_str()<<"]"<<"Interface index["<<itfInd<<"]";
|
||||
emit route_avaible(QString::fromStdString(ip),
|
||||
QString::fromStdString(msk),
|
||||
QString::fromStdString(gw),
|
||||
QString::fromStdString(itf),
|
||||
itfInd);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
break;
|
||||
case RASCS_Disconnected:
|
||||
setConnectionState(Disconnected);
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
break;
|
||||
default:
|
||||
qDebug()<<__FUNCTION__ << __LINE__;
|
||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -220,7 +176,6 @@ void Ikev2Protocol::readIkev2Configuration(const QJsonObject &configuration)
|
||||
|
||||
ErrorCode Ikev2Protocol::start()
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
QByteArray cert = QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8());
|
||||
setConnectionState(Connecting);
|
||||
|
||||
@@ -245,18 +200,15 @@ ErrorCode Ikev2Protocol::start()
|
||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||
}
|
||||
certInstallProcess->setProgram("certutil");
|
||||
QStringList arguments({"-f" , "-p", m_config[config_key::password].toString(),
|
||||
"-importpfx", certFile.fileName(), "NoExport"
|
||||
QStringList arguments({"-f" , "-importpfx",
|
||||
"-p", m_config[config_key::password].toString(),
|
||||
certFile.fileName(), "NoExport"
|
||||
});
|
||||
certInstallProcess->setArguments(arguments);
|
||||
|
||||
connect(certInstallProcess.data(), &PrivilegedProcess::errorOccurred, [certInstallProcess](QProcess::ProcessError error) {
|
||||
qDebug() << "PrivilegedProcess errorOccurred" << error;
|
||||
});
|
||||
|
||||
certInstallProcess->start();
|
||||
}
|
||||
///*
|
||||
// /*
|
||||
{
|
||||
if ( disconnect_vpn()){
|
||||
qDebug()<<"VPN was disconnected";
|
||||
@@ -267,8 +219,10 @@ ErrorCode Ikev2Protocol::start()
|
||||
}
|
||||
|
||||
{
|
||||
if ( !create_new_vpn(tunnelName(), m_config[config_key::hostName].toString())){
|
||||
qDebug() <<"Can't create the VPN connect";
|
||||
{
|
||||
if ( !create_new_vpn(tunnelName(), m_config[config_key::hostName].toString())){
|
||||
qDebug() <<"Can't create the VPN connect";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,14 +251,10 @@ ErrorCode Ikev2Protocol::start()
|
||||
qDebug()<<"We can't connect to VPN";
|
||||
}
|
||||
}
|
||||
//setConnectionState(Connecting);
|
||||
return ErrorCode::NoError;
|
||||
#else
|
||||
return ErrorCode::NoError;
|
||||
#endif
|
||||
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
#ifdef Q_OS_WINDOWS
|
||||
bool Ikev2Protocol::create_new_vpn(const QString & vpn_name,
|
||||
const QString & serv_addr){
|
||||
|
||||
@@ -364,7 +314,7 @@ bool Ikev2Protocol::disconnect_vpn(){
|
||||
|
||||
return true;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
void WINAPI RasDialFuncCallback(UINT unMsg,
|
||||
RASCONNSTATE rasconnstate,
|
||||
DWORD dwError ){
|
||||
@@ -373,6 +323,3 @@ void WINAPI RasDialFuncCallback(UINT unMsg,
|
||||
self->newConnectionStateEventReceived(unMsg, rasconnstate, dwError);
|
||||
}
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef IPSEC_PROTOCOL_H
|
||||
#define IPSEC_PROTOCOL_H
|
||||
#ifndef IKEV2_VPN_PROTOCOL_WINDOWS_H
|
||||
#define IKEV2_VPN_PROTOCOL_WINDOWS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "vpnprotocol.h"
|
||||
#include "core/ipcclient.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
@@ -31,8 +30,6 @@
|
||||
#pragma comment(lib, "rasapi32.lib")
|
||||
#pragma comment(lib, "Crypt32.lib")
|
||||
|
||||
#endif
|
||||
|
||||
class Ikev2Protocol : public VpnProtocol
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -54,14 +51,9 @@ public:
|
||||
private:
|
||||
void readIkev2Configuration(const QJsonObject &configuration);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
//certificates variables
|
||||
|
||||
#endif
|
||||
private:
|
||||
QJsonObject m_config;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
//RAS functions and parametrs
|
||||
HRASCONN hRasConn{nullptr};
|
||||
bool create_new_vpn(const QString & vpn_name,
|
||||
@@ -70,12 +62,8 @@ private:
|
||||
|
||||
bool connect_to_vpn(const QString & vpn_name);
|
||||
bool disconnect_vpn();
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
//#ifdef Q_OS_WIN
|
||||
//DWORD CALLBACK rasCallback(UINT msg, RASCONNSTATE rascs, DWORD err);
|
||||
//#endif
|
||||
DWORD CALLBACK rasCallback(UINT msg, RASCONNSTATE rascs, DWORD err);
|
||||
|
||||
#endif // IPSEC_PROTOCOL_H
|
||||
#endif // IKEV2_VPN_PROTOCOL_WINDOWS_H
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "vpnprotocol.h"
|
||||
#include "protocols/protocols_defs.h"
|
||||
#include "json.h"
|
||||
|
||||
using namespace amnezia;
|
||||
|
||||
@@ -45,6 +46,12 @@ private:
|
||||
bool m_serviceConnected = false;
|
||||
bool m_checkingStatus = false;
|
||||
std::function<void(const QString&)> m_logCallback;
|
||||
|
||||
void setupWireguardProtocol(const QtJson::JsonObject& result);
|
||||
void setupOpenVPNProtocol(const QtJson::JsonObject& result);
|
||||
|
||||
void launchWireguardTunnel(const QtJson::JsonObject &result);
|
||||
void launchOpenVPNTunnel(const QtJson::JsonObject &result);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
#include "json.h"
|
||||
|
||||
#include "ipaddressrange.h"
|
||||
#include "ios_vpnprotocol.h"
|
||||
#include "core/errorstrings.h"
|
||||
@@ -21,6 +19,7 @@ namespace
|
||||
{
|
||||
IOSVpnProtocol* s_instance = nullptr;
|
||||
IOSVpnProtocolImpl* m_controller = nullptr;
|
||||
Proto currentProto = amnezia::Proto::Any;
|
||||
}
|
||||
|
||||
IOSVpnProtocol::IOSVpnProtocol(Proto proto, const QJsonObject &configuration, QObject* parent)
|
||||
@@ -35,10 +34,9 @@ bool IOSVpnProtocol::initialize()
|
||||
{
|
||||
qDebug() << "Initializing Swift Controller";
|
||||
|
||||
static bool creating = false;
|
||||
// No nested creation!
|
||||
Q_ASSERT(creating == false);
|
||||
creating = true;
|
||||
|
||||
// qDebug() << "config =>";
|
||||
// qDebug() << QJsonDocument(m_rawConfig).toJson();
|
||||
|
||||
if (!m_controller) {
|
||||
bool ok;
|
||||
@@ -49,142 +47,69 @@ bool IOSVpnProtocol::initialize()
|
||||
return false;
|
||||
}
|
||||
|
||||
QString vpnProto = result["protocol"].toString();
|
||||
qDebug() << "protocol: " << vpnProto;
|
||||
qDebug() << "config data => ";
|
||||
QtJson::JsonObject config = result["wireguard_config_data"].toMap();
|
||||
|
||||
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();
|
||||
QString pubkey = config["config"].toString().split("\n").takeAt(6).split(" = ").takeLast();
|
||||
QString presharedkey = config["config"].toString().split("\n").takeAt(7).split(" = ").takeLast();
|
||||
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) {
|
||||
case ConnectionStateError: {
|
||||
[m_controller dealloc];
|
||||
m_controller = nullptr;
|
||||
emit connectionStateChanged(VpnConnectionState::Error);
|
||||
return;
|
||||
}
|
||||
case ConnectionStateConnected: {
|
||||
Q_ASSERT(date);
|
||||
QDateTime qtDate(QDateTime::fromNSDate(date));
|
||||
emit connectionStateChanged(VpnConnectionState::Connected);
|
||||
return;
|
||||
}
|
||||
case ConnectionStateDisconnected:
|
||||
// Just in case we are connecting, let's call disconnect.
|
||||
[m_controller disconnect];
|
||||
emit connectionStateChanged(VpnConnectionState::Disconnected);
|
||||
return;
|
||||
}
|
||||
QString protoName = result["protocol"].toString();
|
||||
qDebug() << "protocol: " << protoName;
|
||||
|
||||
if (protoName == "wireguard") {
|
||||
setupWireguardProtocol(result);
|
||||
currentProto = amnezia::Proto::WireGuard;
|
||||
} else if (protoName == "openvpn") {
|
||||
setupOpenVPNProtocol(result);
|
||||
currentProto = amnezia::Proto::OpenVpn;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
callback:^(BOOL a_connected) {
|
||||
qDebug() << "State changed: " << a_connected;
|
||||
if (a_connected) {
|
||||
emit connectionStateChanged(Connected);
|
||||
return;
|
||||
}
|
||||
// emit connectionStateChanged(Disconnected);
|
||||
}];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
QString protocol = result["protocol"].toString();
|
||||
QtJson::JsonObject config = result["wireguard_config_data"].toMap();
|
||||
|
||||
QString clientPrivateKey = config["client_priv_key"].toString();
|
||||
QByteArray key = QByteArray::fromBase64(clientPrivateKey.toLocal8Bit());
|
||||
QString clientPubKey = config["client_pub_key"].toString();
|
||||
|
||||
QString addr = config["config"].toString().split("\n").takeAt(1).split(" = ").takeLast();
|
||||
QStringList dnsServersList = config["config"].toString().split("\n").takeAt(2).split(" = ").takeLast().split(", ");
|
||||
QString privkey = config["config"].toString().split("\n").takeAt(3).split(" = ").takeLast();
|
||||
QString pubkey = config["config"].toString().split("\n").takeAt(6).split(" = ").takeLast();
|
||||
QString presharedkey = config["config"].toString().split("\n").takeAt(7).split(" = ").takeLast();
|
||||
QStringList allowedIPList = config["config"].toString().split("\n").takeAt(8).split(" = ").takeLast().split(", ");
|
||||
QString endpoint = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast();
|
||||
QString serverAddr = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast().split(":").takeFirst();
|
||||
QString port = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast().split(":").takeLast();
|
||||
QString keepalive = config["config"].toString().split("\n").takeAt(10).split(" = ").takeLast();
|
||||
|
||||
QString hostname = config["hostName"].toString();
|
||||
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) {
|
||||
VPNIPAddressRange* range =
|
||||
[[VPNIPAddressRange alloc] initWithAddress:item.ipAddress().toNSString()
|
||||
networkPrefixLength:item.range()
|
||||
isIpv6:item.type() == IPAddressRange::IPv6];
|
||||
[allowedIPAddressRangesNS addObject:[range autorelease]];
|
||||
switch (m_protocol) {
|
||||
case amnezia::Proto::OpenVpn:
|
||||
if (currentProto == amnezia::Proto::WireGuard) {
|
||||
if (m_controller) {
|
||||
stop();
|
||||
initialize();
|
||||
}
|
||||
launchOpenVPNTunnel(result);
|
||||
currentProto = amnezia::Proto::OpenVpn;
|
||||
return NoError;
|
||||
}
|
||||
initialize();
|
||||
launchOpenVPNTunnel(result);
|
||||
break;
|
||||
case amnezia::Proto::WireGuard:
|
||||
if (currentProto == amnezia::Proto::OpenVpn) {
|
||||
if (m_controller) {
|
||||
stop();
|
||||
initialize();
|
||||
}
|
||||
launchWireguardTunnel(result);
|
||||
currentProto = amnezia::Proto::WireGuard;
|
||||
return NoError;
|
||||
}
|
||||
initialize();
|
||||
launchWireguardTunnel(result);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
[m_controller connectWithDnsServer:dnsServersList.takeFirst().toNSString()
|
||||
serverIpv6Gateway:@"FE80::1"
|
||||
serverPublicKey:serverPubKey.toNSString()
|
||||
presharedKey:pskKey.toNSString()
|
||||
serverIpv4AddrIn:serverAddr.toNSString()
|
||||
serverPort:port.toInt()
|
||||
allowedIPAddressRanges:allowedIPAddressRangesNS
|
||||
ipv6Enabled:NO
|
||||
reason:0
|
||||
failureCallback:^() {
|
||||
qDebug() << "IOSVPNProtocol - connection failed";
|
||||
emit connectionStateChanged(Disconnected);
|
||||
}];
|
||||
return NoError;
|
||||
}
|
||||
|
||||
@@ -192,11 +117,21 @@ void IOSVpnProtocol::stop()
|
||||
{
|
||||
if (!m_controller) {
|
||||
qDebug() << "Not correctly initialized";
|
||||
emit connectionStateChanged(Disconnected);
|
||||
|
||||
// dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// emit connectionStateChanged(Disconnected);
|
||||
// });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
[m_controller disconnect];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
emit connectionStateChanged(Disconnected);
|
||||
});
|
||||
|
||||
[m_controller dealloc];
|
||||
m_controller = nullptr;
|
||||
}
|
||||
|
||||
void IOSVpnProtocol::resume_start()
|
||||
@@ -296,3 +231,225 @@ void IOSVpnProtocol::cleanupBackendLogs()
|
||||
file.remove();
|
||||
}
|
||||
|
||||
void IOSVpnProtocol::setupWireguardProtocol(const QtJson::JsonObject &result)
|
||||
{
|
||||
static bool creating = false;
|
||||
// No nested creation!
|
||||
Q_ASSERT(creating == false);
|
||||
creating = true;
|
||||
|
||||
QtJson::JsonObject config = result["wireguard_config_data"].toMap();
|
||||
|
||||
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();
|
||||
QString pubkey = config["config"].toString().split("\n").takeAt(6).split(" = ").takeLast();
|
||||
QString presharedkey = config["config"].toString().split("\n").takeAt(7).split(" = ").takeLast();
|
||||
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) {
|
||||
case ConnectionStateError: {
|
||||
[m_controller dealloc];
|
||||
m_controller = nullptr;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
emit connectionStateChanged(VpnConnectionState::Error);
|
||||
});
|
||||
return;
|
||||
}
|
||||
case ConnectionStateConnected: {
|
||||
Q_ASSERT(date);
|
||||
QDateTime qtDate(QDateTime::fromNSDate(date));
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
emit connectionStateChanged(VpnConnectionState::Connected);
|
||||
});
|
||||
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);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback:^(BOOL a_connected) {
|
||||
if (currentProto != m_protocol) {
|
||||
qDebug() << "Protocols switched: " << a_connected;
|
||||
return;
|
||||
}
|
||||
qDebug() << "State changed: " << a_connected;
|
||||
if (a_connected) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
emit connectionStateChanged(Connected);
|
||||
});
|
||||
return;
|
||||
}
|
||||
// dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// emit connectionStateChanged(Disconnected);
|
||||
// });
|
||||
}];
|
||||
}
|
||||
|
||||
void IOSVpnProtocol::setupOpenVPNProtocol(const QtJson::JsonObject &result)
|
||||
{
|
||||
static bool creating = false;
|
||||
// No nested creation!
|
||||
Q_ASSERT(creating == false);
|
||||
creating = true;
|
||||
|
||||
QtJson::JsonObject ovpn = result["openvpn_config_data"].toMap();
|
||||
QString ovpnConfig = ovpn["config"].toString();
|
||||
// qDebug() << ovpn;
|
||||
|
||||
m_controller = [[IOSVpnProtocolImpl alloc] initWithBundleID:@VPN_NE_BUNDLEID
|
||||
config:ovpnConfig.toNSString()
|
||||
closure:^(ConnectionState state, NSDate* date) {
|
||||
qDebug() << "OVPN Creation completed with connection state:" << state;
|
||||
creating = false;
|
||||
|
||||
switch (state) {
|
||||
case ConnectionStateError: {
|
||||
[m_controller dealloc];
|
||||
m_controller = nullptr;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
emit connectionStateChanged(VpnConnectionState::Error);
|
||||
});
|
||||
return;
|
||||
}
|
||||
case ConnectionStateConnected: {
|
||||
Q_ASSERT(date);
|
||||
QDateTime qtDate(QDateTime::fromNSDate(date));
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
emit connectionStateChanged(VpnConnectionState::Connected);
|
||||
});
|
||||
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);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback:^(BOOL a_connected) {
|
||||
if (currentProto != m_protocol) {
|
||||
qDebug() << "Protocols switched: " << a_connected;
|
||||
return;
|
||||
}
|
||||
qDebug() << "OVPN State changed: " << a_connected;
|
||||
if (a_connected) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
emit connectionStateChanged(Connected);
|
||||
});
|
||||
return;
|
||||
}
|
||||
// dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// emit connectionStateChanged(Disconnected);
|
||||
// });
|
||||
}];
|
||||
}
|
||||
|
||||
void IOSVpnProtocol::launchWireguardTunnel(const QtJson::JsonObject &result)
|
||||
{
|
||||
QtJson::JsonObject config = result["wireguard_config_data"].toMap();
|
||||
|
||||
QString clientPrivateKey = config["client_priv_key"].toString();
|
||||
QByteArray key = QByteArray::fromBase64(clientPrivateKey.toLocal8Bit());
|
||||
QString clientPubKey = config["client_pub_key"].toString();
|
||||
|
||||
QString addr = config["config"].toString().split("\n").takeAt(1).split(" = ").takeLast();
|
||||
QStringList dnsServersList = config["config"].toString().split("\n").takeAt(2).split(" = ").takeLast().split(", ");
|
||||
QString privkey = config["config"].toString().split("\n").takeAt(3).split(" = ").takeLast();
|
||||
QString pubkey = config["config"].toString().split("\n").takeAt(6).split(" = ").takeLast();
|
||||
QString presharedkey = config["config"].toString().split("\n").takeAt(7).split(" = ").takeLast();
|
||||
QStringList allowedIPList = config["config"].toString().split("\n").takeAt(8).split(" = ").takeLast().split(", ");
|
||||
QString endpoint = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast();
|
||||
QString serverAddr = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast().split(":").takeFirst();
|
||||
QString port = config["config"].toString().split("\n").takeAt(9).split(" = ").takeLast().split(":").takeLast();
|
||||
QString keepalive = config["config"].toString().split("\n").takeAt(10).split(" = ").takeLast();
|
||||
|
||||
QString hostname = config["hostName"].toString();
|
||||
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) {
|
||||
VPNIPAddressRange* range =
|
||||
[[VPNIPAddressRange alloc] initWithAddress:item.ipAddress().toNSString()
|
||||
networkPrefixLength:item.range()
|
||||
isIpv6:item.type() == IPAddressRange::IPv6];
|
||||
[allowedIPAddressRangesNS addObject:[range autorelease]];
|
||||
}
|
||||
|
||||
[m_controller connectWithDnsServer:dnsServersList.takeFirst().toNSString()
|
||||
serverIpv6Gateway:@"FE80::1"
|
||||
serverPublicKey:serverPubKey.toNSString()
|
||||
presharedKey:pskKey.toNSString()
|
||||
serverIpv4AddrIn:serverAddr.toNSString()
|
||||
serverPort:port.toInt()
|
||||
allowedIPAddressRanges:allowedIPAddressRangesNS
|
||||
ipv6Enabled:NO
|
||||
reason:0
|
||||
failureCallback:^() {
|
||||
qDebug() << "Wireguard Protocol - connection failed";
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
emit connectionStateChanged(Disconnected);
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
void IOSVpnProtocol::launchOpenVPNTunnel(const QtJson::JsonObject &result)
|
||||
{
|
||||
QtJson::JsonObject ovpn = result["openvpn_config_data"].toMap();
|
||||
QString ovpnConfig = ovpn["config"].toString();
|
||||
|
||||
[m_controller connectWithOvpnConfig:ovpnConfig.toNSString()
|
||||
failureCallback:^{
|
||||
qDebug() << "IOSVPNProtocol - connection failed";
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
emit connectionStateChanged(Disconnected);
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -159,8 +159,8 @@ ErrorCode OpenVpnProtocol::start()
|
||||
return lastError();
|
||||
}
|
||||
|
||||
QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log";
|
||||
Utils::createEmptyFile(vpnLogFileNamePath);
|
||||
// QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log";
|
||||
// Utils::createEmptyFile(vpnLogFileNamePath);
|
||||
|
||||
if (!m_managementServer.start(m_managementHost, m_managementPort)) {
|
||||
setLastError(ErrorCode::OpenVpnManagementServerError);
|
||||
@@ -185,10 +185,9 @@ ErrorCode OpenVpnProtocol::start()
|
||||
}
|
||||
m_openVpnProcess->setProgram(openVpnExecPath());
|
||||
QStringList arguments({"--config" , configPath(),
|
||||
"--management", m_managementHost, QString::number(m_managementPort),
|
||||
"--management-client",
|
||||
"--log", vpnLogFileNamePath
|
||||
});
|
||||
"--management", m_managementHost, QString::number(m_managementPort),
|
||||
"--management-client"/*, "--log", vpnLogFileNamePath */
|
||||
});
|
||||
m_openVpnProcess->setArguments(arguments);
|
||||
|
||||
qDebug() << arguments.join(" ");
|
||||
@@ -234,6 +233,7 @@ void OpenVpnProtocol::onReadyReadDataFromManagementServer()
|
||||
{
|
||||
for (;;) {
|
||||
QString line = m_managementServer.readLine().simplified();
|
||||
|
||||
if (line.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -249,42 +249,6 @@ void OpenVpnProtocol::onReadyReadDataFromManagementServer()
|
||||
sendByteCount();
|
||||
stopTimeoutTimer();
|
||||
setConnectionState(VpnProtocol::Connected);
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::seconds(4));
|
||||
std::string p1,p2,p3;
|
||||
const auto &ret = adpInfo.get_adapter_info("TAP-Windows Adapter V9");
|
||||
if (std::get<0>(ret) == false){
|
||||
p1 = adpInfo.get_adapter_route_gateway();
|
||||
p2 = adpInfo.get_adapter_local_address();
|
||||
p3 = adpInfo.get_adapter_local_gateway();
|
||||
m_routeGateway = QString::fromStdString(p1);
|
||||
m_vpnLocalAddress = QString::fromStdString(p2);
|
||||
m_vpnGateway = QString::fromStdString(p3);
|
||||
qDebug()<<"My openvpn m_routeGateway "<<m_routeGateway;
|
||||
qDebug()<<"My openvpn m_vpnLocalAddress "<<m_vpnLocalAddress;
|
||||
qDebug()<<"My openvpn m_vpnGateway "<< m_vpnGateway;
|
||||
auto ret = adpinfo::get_route_table(p2.c_str());
|
||||
{
|
||||
for (const auto &itret: ret){
|
||||
const auto ip = itret.szDestIp;//std::get<0>(itret);
|
||||
const auto msk = itret.szMaskIp;//std::get<1>(itret);
|
||||
const auto gw = itret.szGatewayIp;//std::get<2>(itret);
|
||||
const auto itf = itret.szInterfaceIp;//std::get<3>(itret);
|
||||
const auto itfInd = itret.ulIfIndex;
|
||||
qDebug()<<"IP["<<ip.c_str()<<"]"<<"Mask["<<msk.c_str()<<"]"<<"gateway["<<gw.c_str()<<"]"<<"Interface["<<itf.c_str()<<"]"<<"Interface index["<<itfInd<<"]";
|
||||
emit route_avaible(QString::fromStdString(ip),
|
||||
QString::fromStdString(msk),
|
||||
QString::fromStdString(gw),
|
||||
QString::fromStdString(itf),
|
||||
itfInd);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else{
|
||||
qDebug()<<"We can't get information about active adapter:"<<QString::fromStdString(std::get<1>(ret));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else if (line.contains("EXITING,SIGTER")) {
|
||||
//openVpnStateSigTermHandler();
|
||||
|
||||
@@ -15,6 +15,10 @@ constexpr char password[] = "password";
|
||||
constexpr char port[] = "port";
|
||||
constexpr char local_port[] = "local_port";
|
||||
|
||||
constexpr char dns1[] = "dns1";
|
||||
constexpr char dns2[] = "dns2";
|
||||
|
||||
|
||||
constexpr char description[] = "description";
|
||||
constexpr char cert[] = "cert";
|
||||
constexpr char config[] = "config";
|
||||
@@ -40,6 +44,7 @@ constexpr char server_priv_key[] = "server_priv_key";
|
||||
constexpr char server_pub_key[] = "server_pub_key";
|
||||
constexpr char psk_key[] = "psk_key";
|
||||
|
||||
constexpr char client_ip[] = "client_ip"; // internal ip address
|
||||
|
||||
constexpr char site[] = "site";
|
||||
constexpr char block_outside_dns[] = "block_outside_dns";
|
||||
@@ -54,6 +59,9 @@ constexpr char last_config[] = "last_config";
|
||||
|
||||
namespace protocols {
|
||||
|
||||
namespace dns {
|
||||
constexpr char amneziaDnsIp[] = "172.29.172.254";
|
||||
}
|
||||
|
||||
namespace openvpn {
|
||||
constexpr char defaultSubnetAddress[] = "10.8.0.0";
|
||||
@@ -89,7 +97,7 @@ constexpr char ckBypassUidKeyPath[] = "/opt/amnezia/cloak/cloak_bypass_uid.key";
|
||||
constexpr char ckAdminKeyPath[] = "/opt/amnezia/cloak/cloak_admin_uid.key";
|
||||
constexpr char defaultPort[] = "443";
|
||||
constexpr char defaultRedirSite[] = "tile.openstreetmap.org";
|
||||
constexpr char defaultCipher[] = "chacha20-ietf-poly1305";
|
||||
constexpr char defaultCipher[] = "chacha20-poly1305";
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
#include "shadowsocksvpnprotocol.h"
|
||||
#include "openvpnovercloakprotocol.h"
|
||||
#include "wireguardprotocol.h"
|
||||
#include "ikev2_vpn_protocol.h"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
#include "ikev2_vpn_protocol_windows.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -100,12 +103,14 @@ QString VpnProtocol::vpnGateway() const
|
||||
VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject& configuration)
|
||||
{
|
||||
switch (container) {
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
|
||||
#endif
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
case DockerContainer::OpenVpn: return new OpenVpnProtocol(configuration);
|
||||
case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration);
|
||||
case DockerContainer::ShadowSocks: return new ShadowSocksVpnProtocol(configuration);
|
||||
case DockerContainer::WireGuard: return new WireguardProtocol(configuration);
|
||||
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
|
||||
#endif
|
||||
default: return nullptr;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include "core/defs.h"
|
||||
#include "containers/containers_defs.h"
|
||||
|
||||
#include "3rd/AdpInfo/netadpinfo.h"
|
||||
|
||||
using namespace amnezia;
|
||||
|
||||
class QTimer;
|
||||
@@ -50,8 +48,6 @@ signals:
|
||||
void timeoutTimerEvent();
|
||||
void protocolError(amnezia::ErrorCode e);
|
||||
|
||||
void route_avaible(QString ip, QString mask, QString gateway, QString interface_ip, unsigned long interface_index);
|
||||
|
||||
public slots:
|
||||
virtual void onTimeout(); // todo: remove?
|
||||
|
||||
@@ -67,7 +63,6 @@ protected:
|
||||
QString m_routeGateway;
|
||||
QString m_vpnLocalAddress;
|
||||
QString m_vpnGateway;
|
||||
adpinfo::NetAdpInfo adpInfo;
|
||||
|
||||
QJsonObject m_rawConfig;
|
||||
|
||||
|
||||
@@ -97,11 +97,26 @@ void WireguardProtocol::readWireguardConfiguration(const QJsonObject &configurat
|
||||
|
||||
}
|
||||
|
||||
//bool WireguardProtocol::openVpnProcessIsRunning() const
|
||||
//{
|
||||
// return Utils::processIsRunning("openvpn");
|
||||
//}
|
||||
|
||||
QString WireguardProtocol::configPath() const
|
||||
{
|
||||
return m_configFileName;
|
||||
}
|
||||
|
||||
void WireguardProtocol::updateRouteGateway(QString line)
|
||||
{
|
||||
// TODO: fix for macos
|
||||
line = line.split("ROUTE_GATEWAY", QString::SkipEmptyParts).at(1);
|
||||
if (!line.contains("/")) return;
|
||||
m_routeGateway = line.split("/", QString::SkipEmptyParts).first();
|
||||
m_routeGateway.replace(" ", "");
|
||||
qDebug() << "Set VPN route gateway" << m_routeGateway;
|
||||
}
|
||||
|
||||
QString WireguardProtocol::wireguardExecPath() const
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
@@ -170,48 +185,8 @@ ErrorCode WireguardProtocol::start()
|
||||
qDebug() << "WireguardProtocol::WireguardProtocol stateChanged" << newState;
|
||||
});
|
||||
|
||||
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::finished, this, [&]() {
|
||||
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::finished, this, [this]() {
|
||||
setConnectionState(VpnConnectionState::Connected);
|
||||
{
|
||||
//TODO:FIXME: without some ugly sleep we have't get a adapter parametrs
|
||||
std::this_thread::sleep_for(std::chrono::seconds(4));
|
||||
std::string p1{},p2{},p3;
|
||||
const auto &ret = adpInfo.get_adapter_info("WireGuard Tunnel");//serviceName().toStdString());//("AmneziaVPN IKEv2");
|
||||
if (std::get<0>(ret) == false){
|
||||
p1 = adpInfo.get_adapter_route_gateway();
|
||||
p2 = adpInfo.get_adapter_local_address();
|
||||
p3 = adpInfo.get_adapter_local_gateway();
|
||||
m_routeGateway = QString::fromStdString(p1);
|
||||
m_vpnLocalAddress = QString::fromStdString(p2);
|
||||
m_vpnGateway = QString::fromStdString(p3);
|
||||
qDebug()<<"My wireguard m_routeGateway "<<m_routeGateway;
|
||||
qDebug()<<"My wireguard m_vpnLocalAddress "<<m_vpnLocalAddress;
|
||||
qDebug()<<"My wireguard m_vpnGateway "<< m_vpnGateway;
|
||||
auto ret = adpinfo::get_route_table(p2.c_str());
|
||||
{
|
||||
for (const auto &itret: ret){
|
||||
const auto ip = itret.szDestIp;//std::get<0>(itret);
|
||||
const auto msk = itret.szMaskIp;//std::get<1>(itret);
|
||||
const auto gw = itret.szGatewayIp;//std::get<2>(itret);
|
||||
const auto itf = itret.szInterfaceIp;//std::get<3>(itret);
|
||||
const auto itfInd = itret.ulIfIndex;
|
||||
qDebug()<<"IP["<<ip.c_str()<<"]"<<"Mask["<<msk.c_str()<<"]"<<"gateway["<<gw.c_str()<<"]"<<"Interface["<<itf.c_str()<<"]"<<"Interface index["<<itfInd<<"]";
|
||||
emit route_avaible(QString::fromStdString(ip),
|
||||
QString::fromStdString(msk),
|
||||
QString::fromStdString(gw),
|
||||
QString::fromStdString(itf),
|
||||
itfInd);
|
||||
//m_vpnGateway = QString::fromStdString(gw);
|
||||
}
|
||||
}
|
||||
//qDebug()<<"My wireguard m_routeGateway "<<m_routeGateway;
|
||||
//qDebug()<<"My wireguard m_vpnLocalAddress "<<m_vpnLocalAddress;
|
||||
//qDebug()<<"My wireguard m_vpnGateway "<< m_vpnGateway;
|
||||
}
|
||||
else{
|
||||
qDebug()<<"We can't get information about active adapter:"<<QString::fromStdString(std::get<1>(ret));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::readyRead, this, [this]() {
|
||||
@@ -243,6 +218,24 @@ ErrorCode WireguardProtocol::start()
|
||||
#endif
|
||||
}
|
||||
|
||||
void WireguardProtocol::updateVpnGateway(const QString &line)
|
||||
{
|
||||
// // line looks like
|
||||
// // PUSH: Received control message: 'PUSH_REPLY,route 10.8.0.1,topology net30,ping 10,ping-restart 120,ifconfig 10.8.0.6 10.8.0.5,peer-id 0,cipher AES-256-GCM'
|
||||
|
||||
// QStringList params = line.split(",");
|
||||
// for (const QString &l : params) {
|
||||
// if (l.contains("ifconfig")) {
|
||||
// if (l.split(" ").size() == 3) {
|
||||
// m_vpnLocalAddress = l.split(" ").at(1);
|
||||
// m_vpnGateway = l.split(" ").at(2);
|
||||
|
||||
// qDebug() << QString("Set vpn local address %1, gw %2").arg(m_vpnLocalAddress).arg(vpnGateway());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
QString WireguardProtocol::serviceName() const
|
||||
{
|
||||
return "AmneziaVPN.WireGuard0";
|
||||
|
||||
@@ -24,8 +24,11 @@ public:
|
||||
private:
|
||||
QString configPath() const;
|
||||
QString wireguardExecPath() const;
|
||||
//bool openVpnProcessIsRunning() const;
|
||||
void readWireguardConfiguration(const QJsonObject &configuration);
|
||||
|
||||
void updateRouteGateway(QString line);
|
||||
void updateVpnGateway(const QString &line);
|
||||
QString serviceName() const;
|
||||
|
||||
|
||||
|
||||
@@ -27,11 +27,9 @@
|
||||
<file>fonts/Lato-Thin.ttf</file>
|
||||
<file>fonts/Lato-ThinItalic.ttf</file>
|
||||
<file>images/AmneziaVPN.png</file>
|
||||
<file>images/server_settings.png</file>
|
||||
<file>images/share.png</file>
|
||||
<file>server_scripts/remove_container.sh</file>
|
||||
<file>server_scripts/setup_host_firewall.sh</file>
|
||||
<file>images/reload.png</file>
|
||||
<file>server_scripts/openvpn_cloak/Dockerfile</file>
|
||||
<file>server_scripts/openvpn_cloak/configure_container.sh</file>
|
||||
<file>server_scripts/openvpn_cloak/start.sh</file>
|
||||
@@ -42,7 +40,6 @@
|
||||
<file>images/check.png</file>
|
||||
<file>images/uncheck.png</file>
|
||||
<file>images/settings_grey.png</file>
|
||||
<file>images/plus.png</file>
|
||||
<file>server_scripts/check_connection.sh</file>
|
||||
<file>server_scripts/remove_all_containers.sh</file>
|
||||
<file>server_scripts/openvpn_cloak/run_container.sh</file>
|
||||
@@ -141,5 +138,24 @@
|
||||
<file>images/animation.gif</file>
|
||||
<file>images/connected.png</file>
|
||||
<file>images/disconnected.png</file>
|
||||
<file>ui/qml/Pages/PageQrDecoder.qml</file>
|
||||
<file>ui/qml/Pages/PageAbout.qml</file>
|
||||
<file>ui/qml/Controls/RichLabelType.qml</file>
|
||||
<file>images/svg/gpp_good_black_24dp.svg</file>
|
||||
<file>ui/qml/Controls/SvgImageType.qml</file>
|
||||
<file>images/svg/gpp_maybe_black_24dp.svg</file>
|
||||
<file>images/svg/close_black_24dp.svg</file>
|
||||
<file>images/svg/delete_black_24dp.svg</file>
|
||||
<file>images/svg/done_black_24dp.svg</file>
|
||||
<file>images/svg/format_list_bulleted_black_24dp.svg</file>
|
||||
<file>images/svg/logout_black_24dp.svg</file>
|
||||
<file>images/svg/miscellaneous_services_black_24dp.svg</file>
|
||||
<file>images/svg/refresh_black_24dp.svg</file>
|
||||
<file>images/svg/settings_black_24dp.svg</file>
|
||||
<file>images/svg/share_black_24dp.svg</file>
|
||||
<file>images/svg/vpn_key_black_24dp.svg</file>
|
||||
<file>images/svg/control_point_black_24dp.svg</file>
|
||||
<file>images/svg/settings_suggest_black_24dp.svg</file>
|
||||
<file>ui/qml/Controls/SvgButtonType.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -39,6 +39,26 @@ error() {
|
||||
printv '' R "$1"
|
||||
}
|
||||
|
||||
XCODEBUILD="/usr/bin/xcodebuild"
|
||||
WORKINGDIR=`pwd`
|
||||
|
||||
compile_openvpn_adapter() {
|
||||
cd 3rd/OpenVPNAdapter
|
||||
|
||||
$XCODEBUILD -scheme OpenVPNAdapter -configuration Debug -xcconfig Configuration/amnezia.xcconfig -sdk iphoneos -destination 'generic/platform=iOS' -project OpenVPNAdapter.xcodeproj
|
||||
|
||||
cd ../../
|
||||
}
|
||||
|
||||
prepare_to_build_vpn() {
|
||||
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/Debug-iphoneos
|
||||
BUILT_PRODUCTS_DIR = $WORKINGDIR/3rd/OpenVPNAdapter/build/Debug-iphoneos
|
||||
EOF
|
||||
}
|
||||
|
||||
die() {
|
||||
if [[ "$1" ]]; then
|
||||
error "$1"
|
||||
|
||||
@@ -126,7 +126,7 @@ printn Y "Retrieve the wireguard-go version... "
|
||||
print G "done."
|
||||
|
||||
printn Y "Cleaning the existing project... "
|
||||
rm -rf mozillavpn.xcodeproj/ || die "Failed to remove things"
|
||||
rm -rf AmneziaVPN.xcodeproj/ || die "Failed to remove things"
|
||||
print G "done."
|
||||
|
||||
#print Y "Importing translation files..."
|
||||
@@ -205,6 +205,16 @@ else
|
||||
print G none
|
||||
fi
|
||||
|
||||
if [ "$OS" = "ios" ]; then
|
||||
print Y "Prepare to build OpenVPNAdapter..."
|
||||
prepare_to_build_vpn
|
||||
print Y "Building OpenVPNAdapter..."
|
||||
compile_openvpn_adapter
|
||||
else
|
||||
print Y "No OpenVPNAdapter will be built"
|
||||
|
||||
fi
|
||||
|
||||
print Y "Creating the xcode project via qmake..."
|
||||
$QMAKE \
|
||||
VERSION=$SHORTVERSION \
|
||||
|
||||
@@ -61,7 +61,8 @@ class XCodeprojPatcher
|
||||
config.build_settings['SWIFT_OBJC_BRIDGING_HEADER'] ||= 'macos/app/WireGuard-Bridging-Header.h'
|
||||
config.build_settings['FRAMEWORK_SEARCH_PATHS'] ||= [
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/3rd"
|
||||
"$(PROJECT_DIR)/3rd",
|
||||
"$(PROJECT_DIR)/3rd/OpenVPNAdapter/build/Debug-iphoneos"
|
||||
]
|
||||
|
||||
# Versions and names
|
||||
@@ -251,6 +252,11 @@ class XCodeprojPatcher
|
||||
config.build_settings['SWIFT_OBJC_BRIDGING_HEADER'] ||= 'macos/networkextension/WireGuardNetworkExtension-Bridging-Header.h'
|
||||
config.build_settings['SWIFT_PRECOMPILE_BRIDGING_HEADER'] = 'NO'
|
||||
config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'YES'
|
||||
config.build_settings['FRAMEWORK_SEARCH_PATHS'] ||= [
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/3rd",
|
||||
"$(PROJECT_DIR)/3rd/OpenVPNAdapter/build/Debug-iphoneos"
|
||||
]
|
||||
|
||||
# Versions and names
|
||||
config.build_settings['MARKETING_VERSION'] ||= shortVersion
|
||||
@@ -350,6 +356,18 @@ class XCodeprojPatcher
|
||||
|
||||
framework_ref = frameworks_group.new_file('NetworkExtension.framework')
|
||||
frameworks_build_phase.add_file_reference(framework_ref)
|
||||
|
||||
framework_ref = frameworks_group.new_file('3rd/OpenVPNAdapter/build/Debug-iphoneos/LZ4.framework')
|
||||
frameworks_build_phase.add_file_reference(framework_ref)
|
||||
|
||||
framework_ref = frameworks_group.new_file('3rd/OpenVPNAdapter/build/Debug-iphoneos/mbedTLS.framework')
|
||||
frameworks_build_phase.add_file_reference(framework_ref)
|
||||
|
||||
framework_ref = frameworks_group.new_file('3rd/OpenVPNAdapter/build/Debug-iphoneos/OpenVPNClient.framework')
|
||||
frameworks_build_phase.add_file_reference(framework_ref)
|
||||
|
||||
framework_ref = frameworks_group.new_file('3rd/OpenVPNAdapter/build/Debug-iphoneos/OpenVPNAdapter.framework')
|
||||
frameworks_build_phase.add_file_reference(framework_ref)
|
||||
|
||||
# This fails: @target_main.add_dependency @target_extension
|
||||
container_proxy = @project.new(Xcodeproj::Project::PBXContainerItemProxy)
|
||||
|
||||
@@ -1,3 +1,48 @@
|
||||
FROM mvance/unbound:latest
|
||||
|
||||
LABEL maintainer="AmneziaVPN"
|
||||
|
||||
RUN echo " \n\
|
||||
domain-insecure: \"coin.\"\n\
|
||||
domain-insecure: \"emc.\"\n\
|
||||
domain-insecure: \"lib.\"\n\
|
||||
domain-insecure: \"bazar.\"\n\
|
||||
domain-insecure: \"enum.\"\n\
|
||||
\n\
|
||||
stub-zone:\n\
|
||||
name: coin.\n\
|
||||
stub-host: seed1.emercoin.com\n\
|
||||
stub-host: seed2.emercoin.com\n\
|
||||
stub-first: yes\n\
|
||||
\n\
|
||||
stub-zone:\n\
|
||||
name: emc.\n\
|
||||
stub-host: seed1.emercoin.com\n\
|
||||
stub-host: seed2.emercoin.com\n\
|
||||
stub-first: yes\n\
|
||||
\n\
|
||||
stub-zone:\n\
|
||||
name: lib.\n\
|
||||
stub-host: seed1.emercoin.com\n\
|
||||
stub-host: seed2.emercoin.com\n\
|
||||
stub-first: yes\n\
|
||||
\n\
|
||||
stub-zone:\n\
|
||||
name: bazar.\n\
|
||||
stub-host: seed1.emercoin.com\n\
|
||||
stub-host: seed2.emercoin.com\n\
|
||||
stub-first: yes\n\
|
||||
\n\
|
||||
stub-zone:\n\
|
||||
name: enum.\n\
|
||||
stub-host: seed1.emercoin.com\n\
|
||||
stub-host: seed2.emercoin.com\n\
|
||||
stub-first: yes\n\
|
||||
\n\
|
||||
forward-zone:\n\
|
||||
name: .\n\
|
||||
forward-tls-upstream: yes\n\
|
||||
forward-addr: 1.1.1.1@853 #cloudflare-dns.com\n\
|
||||
forward-addr: 1.0.0.1@853 #cloudflare-dns.com\n\
|
||||
" | tee /opt/unbound/etc/unbound/forward-records.conf
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# Run container
|
||||
sudo docker run -d --restart always --cap-add=NET_ADMIN -p 53:53/udp -p 53:53/tcp --name $CONTAINER_NAME $CONTAINER_NAME
|
||||
sudo docker run -d --restart always --network amnezia-dns-net --ip=172.29.172.254 --name $CONTAINER_NAME $CONTAINER_NAME
|
||||
|
||||
@@ -5,3 +5,4 @@ sudo docker run \
|
||||
-d --privileged \
|
||||
--name $CONTAINER_NAME $CONTAINER_NAME
|
||||
|
||||
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:latest
|
||||
FROM alpine:3.15
|
||||
|
||||
LABEL maintainer="AmneziaVPN"
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Run container
|
||||
sudo docker run -d --restart always --cap-add=NET_ADMIN -p $OPENVPN_PORT:$OPENVPN_PORT/$OPENVPN_TRANSPORT_PROTO --name $CONTAINER_NAME $CONTAINER_NAME
|
||||
sudo docker run \
|
||||
-d --restart always \
|
||||
--cap-add=NET_ADMIN \
|
||||
-p $OPENVPN_PORT:$OPENVPN_PORT/$OPENVPN_TRANSPORT_PROTO \
|
||||
--name $CONTAINER_NAME $CONTAINER_NAME
|
||||
|
||||
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
|
||||
|
||||
# Create tun device if not exist
|
||||
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'
|
||||
|
||||