Compare commits

..

58 Commits

Author SHA1 Message Date
pokamest
c5ef462937 v. 2.0.10 2022-06-11 15:52:44 +03:00
Pokamest Nikak
eca397b45f Docker fixes - FROM alpine:3.15 2022-06-10 16:19:29 +03:00
Grigory Dobrov
4829c8b314 Merge branch 'fix_inf_windows' into dev 2022-04-17 08:33:46 +03:00
Grigory Dobrov
94d29796b8 fixed line endings for windows drivers *.inf files 2022-04-13 00:45:19 +03:00
pokamest
a6a69ab1b6 cert updated 2022-03-26 23:15:29 +03:00
pokamest
912051637a Android manifest fix, IPC refactoring 2022-02-22 02:08:57 +03:00
pokamest
c233f767f4 Multiple ui fixes, save file function reimpl 2022-02-15 17:08:55 +03:00
aman
b63bf2465f Android service issue fixed - VPN is keep running when connected and ui closed 2022-02-13 22:52:04 +05:30
pokamest
505c9c6218 Various fixes 2022-02-09 15:23:20 +03:00
pokamest
14350240eb Merge branch 'dev' 2022-02-07 08:42:52 +03:00
pokamest
cb21991efa DNS container fix, Cloak binaries updated 2022-02-05 18:02:49 +03:00
pokamest
49e58c25f2 Installer version bump 2022-02-05 16:08:53 +03:00
pokamest
ac6000a2ae Svg icons, dns ui fix 2022-02-05 15:52:14 +03:00
pokamest
6d1c9edc24 Log panel added 2022-02-04 17:49:48 +03:00
pokamest
1a7fa3746d DNS service fixes for all containers 2022-02-02 02:12:29 +03:00
pokamest
f7a57ffeb4 Cloak container arm support, ss updated 2022-02-02 01:52:37 +03:00
pokamest
ad9d45a154 Dns selection implemented 2022-02-01 19:48:59 +03:00
pokamest
5fffb2afe3 Dns container to internal network 2022-01-31 16:08:22 +03:00
pokamest
1269114074 Cleanup berfore uninstall, post-uninstall refactoring 2022-01-31 00:10:51 +03:00
pokamest
d24f6ae064 Logs functions fixes 2022-01-30 17:35:57 +03:00
pokamest
95fe09489c Vpn and wizard pages fixes 2022-01-28 16:03:21 +03:00
pokamest
1a144da36d SFTP fixes for Macos 2022-01-24 14:29:37 -08:00
pokamest
8e26da1759 Macos build fixes 2022-01-23 15:25:53 -08:00
pokamest
daf53226c3 SFTP fixes 2022-01-24 02:01:56 +03:00
pokamest
2b9e615e51 Various fixes 2022-01-23 19:16:40 +03:00
pokamest
02acbecef5 Re-resolve sites after VPN Connected 2022-01-22 20:00:06 +03:00
pokamest
8f28964ce2 Tiny ui fixes 2022-01-22 18:19:57 +03:00
pokamest
495e74e2f0 Sites page fix 2022-01-22 18:19:38 +03:00
pokamest
8f23970ccc Gradle build bump 2022-01-04 17:12:32 +03:00
pokamest
9ec39658fe DNS container with EmerCoin DNS support 2022-01-03 18:30:53 +03:00
pokamest
9943e081d9 RegExp validators fix 2021-12-25 23:01:53 +03:00
pokamest
68a51c9c63 WireGuard protocol fix 2021-12-25 21:14:55 +03:00
pokamest
e7dd964825 ServerController fix 2021-12-22 13:41:09 +03:00
pokamest
f20134415e IKEv2 class file renamed 2021-12-21 02:57:23 +03:00
pokamest
bd9b9600c1 Release 2.0.6 2021-12-21 00:35:18 +03:00
pokamest
5ae9873455 Destructor crash fix 2021-12-20 15:43:36 +03:00
pokamest
5776ca0384 Merge pull request #47 from amnezia-vpn/qr_rework
Qr rework
2021-12-20 03:23:48 +03:00
pokamest
f8f4b39965 qzxing submodule 2021-12-20 02:42:16 +03:00
pokamest
1d51419a11 QR codes rework 2021-12-20 02:29:23 +03:00
pokamest
5e1ca0c19f iOS icons asset 2021-12-16 11:54:07 -08:00
pokamest
b341224c92 AppStore icon fix 2021-12-16 15:04:59 +03:00
pokamest
3861f23af3 iOS icon fixed 2021-12-16 14:45:08 +03:00
pokamest
e7beff79d0 iOS icons 2021-12-16 14:38:41 +03:00
pokamest
2380875cbf Merge branch 'ios-wireguard' into dev 2021-12-15 06:06:08 -08:00
pokamest
343e6a50df resetIpStack added 2021-12-15 14:53:07 +03:00
pokamest
5aa47d35e7 Version to main screen 2021-12-14 12:50:57 +03:00
pokamest
313ceed1d0 StartPageLogic fix 2021-12-12 14:42:25 +03:00
pokamest
ac07d62344 ui fixes 2021-12-11 14:44:24 +03:00
pokamest
2db1bbae4b WireGuard server script fix 2021-12-10 15:43:43 +03:00
Alex Kh
090e50e936 [WIP] protocol switching and relaunch crash issues (possibly) fixed 2021-12-09 12:59:56 +04:00
Alex Kh
b6bab0c723 [WIP] seamless protocol switching without leaving the app 2021-12-08 19:40:43 +04:00
Alex Kh
1a333f7968 [WIP] move connection state call to main thread 2021-12-08 17:10:15 +04:00
Alex Kh
87c00b3804 Merge branch 'ios-wireguard' of https://github.com/amnezia-vpn/desktop-client into ios-wireguard 2021-12-08 15:57:16 +04:00
Alex Kh
eba71469a4 [WIP] OpenVPN tunnel implementation 2021-12-08 15:55:36 +04:00
pokamest
4eef127744 VPN modes ui fix 2021-12-04 19:48:47 +03:00
pokamest
1ce26b3ada Merge pull request #43 from boscogh/master
dockerfiles: Added support of Shadowsocks for aarch64
2021-10-25 16:37:39 +03:00
Pavel Malyutin
e7092ae769 dockerfiles: Added support of Shadowsocks for aarch64 2021-10-20 10:26:33 +00:00
pokamest
b8b0ffb626 Merge pull request #21 from amnezia-vpn/dev
Release 1.8.1
2021-06-24 16:48:50 +03:00
200 changed files with 4285 additions and 6476 deletions

4
.gitattributes vendored Normal file
View 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
View File

@@ -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
View File

@@ -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

View File

@@ -2,5 +2,5 @@ TEMPLATE = subdirs
SUBDIRS = client
!ios:!android {
SUBDIRS += service platform
SUBDIRS += service
}

View File

@@ -1,7 +0,0 @@
HEADERS += \
3rd/AdpInfo/netadpinfo.h \
win32: {
SOURCES += \
3rd/AdpInfo/win_netadpinfo.cc \
}

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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_)

View File

@@ -1,5 +0,0 @@
HEADERS += \
3rd/QRCodeGenerator/QRCodeGenerator.h \
SOURCES += \
3rd/QRCodeGenerator/QRCodeGenerator.cpp \

View File

@@ -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
}

View File

@@ -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

Submodule client/3rd/qzxing added at 2fd4dd60c0

View File

@@ -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;

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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?
}
}

View File

@@ -0,0 +1,6 @@
package org.ftylitak.qzxing;
public class NativeFunctions {
public static native void onPermissionsGranted();
public static native void onPermissionsDenied();
}

View File

@@ -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;
}
}
}
}

View 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);
}
}

View File

@@ -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

View File

@@ -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";

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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);
};

View File

@@ -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,

View File

@@ -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:

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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) }});

View File

@@ -5,6 +5,7 @@
#include <QObject>
#include "sshconnection.h"
#include "sshremoteprocess.h"
#include "debug.h"
#include "defs.h"
#include "settings.h"

View File

@@ -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();
}

View File

@@ -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;

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 454 B

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -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();
}

View 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

View 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

View File

@@ -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
}
}

View File

@@ -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
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
};

View File

@@ -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);
});
}];
}

View File

@@ -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();

View File

@@ -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";
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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";

View File

@@ -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;

View File

@@ -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>

View File

@@ -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"

View File

@@ -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 \

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -5,3 +5,4 @@ sudo docker run \
-d --privileged \
--name $CONTAINER_NAME $CONTAINER_NAME
sudo docker network connect amnezia-dns-net $CONTAINER_NAME

View File

@@ -1,4 +1,4 @@
FROM alpine:latest
FROM alpine:3.15
LABEL maintainer="AmneziaVPN"

View File

@@ -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'

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