mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-21 02:01:03 +07:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 20989ea832 | |||
| 1909d3c94e | |||
| 10a107716c | |||
| 5445e6637b |
@@ -10,6 +10,7 @@ include(${CLIENT_ROOT_DIR}/3rd/qrcodegen/qrcodegen.cmake)
|
||||
|
||||
set(LIBSSH_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/libssh/")
|
||||
set(OPENSSL_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/openssl/")
|
||||
set(LIBXRAY_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/libxray")
|
||||
|
||||
set(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib")
|
||||
|
||||
@@ -27,6 +28,9 @@ if(WIN32)
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libcrypto.lib")
|
||||
endif()
|
||||
elseif(APPLE AND NOT IOS)
|
||||
set(LIBS ${LIBS} "resolv")
|
||||
set(LIBXRAY_LIB_PATH "${LIBXRAY_ROOT_DIR}/macos/x86_64/libxray.a")
|
||||
set(LIBXRAY_INCLUDE_DIR "${LIBXRAY_ROOT_DIR}/macos/x86_64")
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libssh.a")
|
||||
set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libz.a")
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/x86_64")
|
||||
@@ -72,6 +76,8 @@ set(LIBS ${LIBS}
|
||||
${OPENSSL_LIB_CRYPTO_PATH}
|
||||
)
|
||||
|
||||
set(LIBS ${LIBS} ${LIBXRAY_LIB_PATH})
|
||||
|
||||
add_compile_definitions(_WINSOCKAPI_)
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||
@@ -88,4 +94,5 @@ include_directories(
|
||||
${CLIENT_ROOT_DIR}/3rd/qtkeychain/qtkeychain
|
||||
${CMAKE_CURRENT_BINARY_DIR}/3rd/qtkeychain
|
||||
${CMAKE_CURRENT_BINARY_DIR}/3rd/libssh/include
|
||||
${LIBXRAY_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
@@ -46,29 +46,59 @@ struct WGConfig: Decodable {
|
||||
}
|
||||
|
||||
var settings: String {
|
||||
junkPacketCount == nil ? "" :
|
||||
"""
|
||||
Jc = \(junkPacketCount!)
|
||||
Jmin = \(junkPacketMinSize!)
|
||||
Jmax = \(junkPacketMaxSize!)
|
||||
S1 = \(initPacketJunkSize!)
|
||||
S2 = \(responsePacketJunkSize!)
|
||||
S3 = \(cookieReplyPacketJunkSize!)
|
||||
S4 = \(transportPacketJunkSize!)
|
||||
H1 = \(initPacketMagicHeader!)
|
||||
H2 = \(responsePacketMagicHeader!)
|
||||
H3 = \(underloadPacketMagicHeader!)
|
||||
H4 = \(transportPacketMagicHeader!)
|
||||
I1 = \(specialJunk1!)
|
||||
I2 = \(specialJunk2!)
|
||||
I3 = \(specialJunk3!)
|
||||
I4 = \(specialJunk4!)
|
||||
I5 = \(specialJunk5!)
|
||||
J1 = \(controlledJunk1!)
|
||||
J2 = \(controlledJunk2!)
|
||||
J3 = \(controlledJunk3!)
|
||||
Itime = \(specialHandshakeTimeout!)
|
||||
"""
|
||||
guard junkPacketCount != nil else { return "" }
|
||||
|
||||
var settingsLines: [String] = []
|
||||
|
||||
// Required parameters when junkPacketCount is present
|
||||
settingsLines.append("Jc = \(junkPacketCount!)")
|
||||
settingsLines.append("Jmin = \(junkPacketMinSize!)")
|
||||
settingsLines.append("Jmax = \(junkPacketMaxSize!)")
|
||||
settingsLines.append("S1 = \(initPacketJunkSize!)")
|
||||
settingsLines.append("S2 = \(responsePacketJunkSize!)")
|
||||
|
||||
settingsLines.append("H1 = \(initPacketMagicHeader!)")
|
||||
settingsLines.append("H2 = \(responsePacketMagicHeader!)")
|
||||
settingsLines.append("H3 = \(underloadPacketMagicHeader!)")
|
||||
settingsLines.append("H4 = \(transportPacketMagicHeader!)")
|
||||
|
||||
// Optional parameters - only add if not nil and not empty
|
||||
if let s3 = cookieReplyPacketJunkSize, !s3.isEmpty {
|
||||
settingsLines.append("S3 = \(s3)")
|
||||
}
|
||||
if let s4 = transportPacketJunkSize, !s4.isEmpty {
|
||||
settingsLines.append("S4 = \(s4)")
|
||||
}
|
||||
|
||||
if let i1 = specialJunk1, !i1.isEmpty {
|
||||
settingsLines.append("I1 = \(i1)")
|
||||
}
|
||||
if let i2 = specialJunk2, !i2.isEmpty {
|
||||
settingsLines.append("I2 = \(i2)")
|
||||
}
|
||||
if let i3 = specialJunk3, !i3.isEmpty {
|
||||
settingsLines.append("I3 = \(i3)")
|
||||
}
|
||||
if let i4 = specialJunk4, !i4.isEmpty {
|
||||
settingsLines.append("I4 = \(i4)")
|
||||
}
|
||||
if let i5 = specialJunk5, !i5.isEmpty {
|
||||
settingsLines.append("I5 = \(i5)")
|
||||
}
|
||||
if let j1 = controlledJunk1, !j1.isEmpty {
|
||||
settingsLines.append("J1 = \(j1)")
|
||||
}
|
||||
if let j2 = controlledJunk2, !j2.isEmpty {
|
||||
settingsLines.append("J2 = \(j2)")
|
||||
}
|
||||
if let j3 = controlledJunk3, !j3.isEmpty {
|
||||
settingsLines.append("J3 = \(j3)")
|
||||
}
|
||||
if let itime = specialHandshakeTimeout, !itime.isEmpty {
|
||||
settingsLines.append("Itime = \(itime)")
|
||||
}
|
||||
|
||||
return settingsLines.joined(separator: "\n")
|
||||
}
|
||||
|
||||
var str: String {
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
#include "xrayprotocol.h"
|
||||
|
||||
#include "core/defs.h"
|
||||
#include "core/networkUtilities.h"
|
||||
#include <QCryptographicHash>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkInterface>
|
||||
#include <QtCore/qcontainerfwd.h>
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qlogging.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "core/networkUtilities.h"
|
||||
#include "utilities.h"
|
||||
#include "core/ipcclient.h"
|
||||
#include "libxray.h"
|
||||
|
||||
XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent) : VpnProtocol(configuration, parent)
|
||||
{
|
||||
@@ -15,6 +31,9 @@ XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent) :
|
||||
m_vpnGateway = amnezia::protocols::xray::defaultLocalAddr;
|
||||
m_vpnLocalAddress = amnezia::protocols::xray::defaultLocalAddr;
|
||||
m_t2sProcess = IpcClient::InterfaceTun2Socks();
|
||||
|
||||
amnezia_xray_setloghandler(&XrayProtocol::ctxLogHandler, this);
|
||||
amnezia_xray_setsockcallback(&XrayProtocol::ctxSockCallback, this);
|
||||
}
|
||||
|
||||
XrayProtocol::~XrayProtocol()
|
||||
@@ -25,61 +44,20 @@ XrayProtocol::~XrayProtocol()
|
||||
|
||||
ErrorCode XrayProtocol::start()
|
||||
{
|
||||
qDebug().noquote() << "XrayProtocol xrayExecPath():" << xrayExecPath();
|
||||
qDebug() << "XrayProtocol::start()";
|
||||
|
||||
if (!QFileInfo::exists(xrayExecPath())) {
|
||||
setLastError(ErrorCode::XrayExecutableMissing);
|
||||
return lastError();
|
||||
auto cfg = QJsonDocument(m_xrayConfig).toJson().toStdString();
|
||||
if (auto err = amnezia_xray_configure(cfg.data()); err != 0) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
m_xrayCfgFile.setAutoRemove(false);
|
||||
#endif
|
||||
m_xrayCfgFile.open();
|
||||
QString config = QJsonDocument(m_xrayConfig).toJson();
|
||||
config.replace(m_remoteHost, m_remoteAddress);
|
||||
m_xrayCfgFile.write(config.toUtf8());
|
||||
m_xrayCfgFile.close();
|
||||
|
||||
QStringList args = QStringList() << "-c" << m_xrayCfgFile.fileName() << "-format=json";
|
||||
|
||||
qDebug().noquote() << "XrayProtocol::start()" << xrayExecPath() << args.join(" ");
|
||||
|
||||
m_xrayProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
m_xrayProcess.setProgram(xrayExecPath());
|
||||
|
||||
if (Utils::processIsRunning(Utils::executable("xray", false))) {
|
||||
qDebug().noquote() << "kill previos xray";
|
||||
Utils::killProcessByName(Utils::executable("xray", false));
|
||||
if (auto err = amnezia_xray_start(); err != 0) {
|
||||
return ErrorCode::NotImplementedError;
|
||||
}
|
||||
|
||||
m_xrayProcess.setArguments(args);
|
||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||
|
||||
connect(&m_xrayProcess, &QProcess::readyReadStandardOutput, this, [this]() {
|
||||
#ifdef QT_DEBUG
|
||||
qDebug().noquote() << "xray:" << m_xrayProcess.readAllStandardOutput();
|
||||
#endif
|
||||
});
|
||||
|
||||
connect(&m_xrayProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this,
|
||||
[this](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
qDebug().noquote() << "XrayProtocol finished, exitCode, exitStatus" << exitCode << exitStatus;
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
if ((exitStatus != QProcess::NormalExit) || (exitCode != 0)) {
|
||||
emit protocolError(amnezia::ErrorCode::XrayExecutableCrashed);
|
||||
emit setConnectionState(Vpn::ConnectionState::Error);
|
||||
}
|
||||
});
|
||||
|
||||
m_xrayProcess.start();
|
||||
m_xrayProcess.waitForStarted();
|
||||
|
||||
if (m_xrayProcess.state() == QProcess::ProcessState::Running) {
|
||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||
QThread::msleep(1000);
|
||||
return startTun2Sock();
|
||||
} else
|
||||
return ErrorCode::XrayExecutableMissing;
|
||||
return startTun2Sock();
|
||||
}
|
||||
|
||||
ErrorCode XrayProtocol::startTun2Sock()
|
||||
@@ -126,9 +104,7 @@ ErrorCode XrayProtocol::startTun2Sock()
|
||||
}
|
||||
#endif
|
||||
if (m_routeMode == Settings::RouteMode::VpnAllSites) {
|
||||
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "0.0.0.0/1");
|
||||
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "128.0.0.0/1");
|
||||
IpcClient::Interface()->routeAddList(m_routeGateway, QStringList() << m_remoteAddress);
|
||||
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "1.0.0.0/8" << "2.0.0.0/7" << "4.0.0.0/6" << "8.0.0.0/5" << "16.0.0.0/4" << "32.0.0.0/3" << "64.0.0.0/2" << "128.0.0.0/1");
|
||||
}
|
||||
IpcClient::Interface()->StopRoutingIpv6();
|
||||
#ifdef Q_OS_WIN
|
||||
@@ -171,9 +147,9 @@ void XrayProtocol::stop()
|
||||
IpcClient::Interface()->StartRoutingIpv6();
|
||||
#endif
|
||||
qDebug() << "XrayProtocol::stop()";
|
||||
m_xrayProcess.disconnect();
|
||||
m_xrayProcess.kill();
|
||||
m_xrayProcess.waitForFinished(3000);
|
||||
|
||||
amnezia_xray_stop();
|
||||
|
||||
if (m_t2sProcess) {
|
||||
m_t2sProcess->stop();
|
||||
}
|
||||
@@ -181,15 +157,6 @@ void XrayProtocol::stop()
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
}
|
||||
|
||||
QString XrayProtocol::xrayExecPath()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
return Utils::executable(QString("xray/xray"), true);
|
||||
#else
|
||||
return Utils::executable(QString("xray"), true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void XrayProtocol::readXrayConfiguration(const QJsonObject &configuration)
|
||||
{
|
||||
m_configData = configuration;
|
||||
@@ -205,3 +172,20 @@ void XrayProtocol::readXrayConfiguration(const QJsonObject &configuration)
|
||||
m_primaryDNS = configuration.value(amnezia::config_key::dns1).toString();
|
||||
m_secondaryDNS = configuration.value(amnezia::config_key::dns2).toString();
|
||||
}
|
||||
|
||||
void XrayProtocol::sockCallback(uintptr_t fd)
|
||||
{
|
||||
// #ifdef Q_OS_DARWIN
|
||||
// const int iface = if_nametoindex("en0");
|
||||
// if (iface > 0)
|
||||
// {
|
||||
// setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface, sizeof(iface));
|
||||
// setsockopt(fd, IPPROTO_IPV6, IPV6_BOUND_IF, &iface, sizeof(iface));
|
||||
// }
|
||||
// #endif
|
||||
}
|
||||
|
||||
void XrayProtocol::logHandler(char* str)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
#include "QProcess"
|
||||
|
||||
#include "containers/containers_defs.h"
|
||||
#include "openvpnprotocol.h"
|
||||
#include "protocols/vpnprotocol.h"
|
||||
#include "rep_ipc_process_tun2socks_replica.h"
|
||||
#include "settings.h"
|
||||
#include <cstdint>
|
||||
|
||||
class XrayProtocol : public VpnProtocol
|
||||
{
|
||||
@@ -24,10 +25,16 @@ protected:
|
||||
QJsonObject m_xrayConfig;
|
||||
|
||||
private:
|
||||
static QString xrayExecPath();
|
||||
static QString tun2SocksExecPath();
|
||||
static void ctxSockCallback(uintptr_t fd, void* ctx) {
|
||||
reinterpret_cast<XrayProtocol*>(ctx)->sockCallback(fd);
|
||||
}
|
||||
static void ctxLogHandler(char* str, void* ctx) {
|
||||
reinterpret_cast<XrayProtocol*>(ctx)->logHandler(str);
|
||||
}
|
||||
|
||||
void sockCallback(uintptr_t fd);
|
||||
void logHandler(char* str);
|
||||
|
||||
private:
|
||||
int m_localPort;
|
||||
QString m_remoteHost;
|
||||
QString m_remoteAddress;
|
||||
|
||||
@@ -221,8 +221,6 @@ namespace
|
||||
|
||||
serverConfig[configKey::apiConfig] = apiConfig;
|
||||
|
||||
qDebug() << serverConfig;
|
||||
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,8 +62,7 @@ PageType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: false
|
||||
// enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
|
||||
enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
|
||||
checked: !SettingsController.strictKillSwitchEnabled
|
||||
|
||||
text: qsTr("Soft KillSwitch")
|
||||
@@ -74,9 +73,7 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
visible: false
|
||||
}
|
||||
DividerType {}
|
||||
|
||||
VerticalRadioButton {
|
||||
id: strictKillSwitch
|
||||
@@ -84,7 +81,9 @@ PageType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
|
||||
visible: false
|
||||
enabled: false
|
||||
// enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
|
||||
checked: SettingsController.strictKillSwitchEnabled
|
||||
|
||||
text: qsTr("Strict KillSwitch")
|
||||
@@ -106,7 +105,9 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
DividerType {
|
||||
visible: false
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.topMargin: 32
|
||||
|
||||
Reference in New Issue
Block a user