mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
env upd
This commit is contained in:
@@ -33,6 +33,17 @@ add_definitions(-DDEV_S3_ENDPOINT="$ENV{DEV_S3_ENDPOINT}")
|
||||
add_definitions(-DFREE_V2_ENDPOINT="$ENV{FREE_V2_ENDPOINT}")
|
||||
add_definitions(-DPREM_V1_ENDPOINT="$ENV{PREM_V1_ENDPOINT}")
|
||||
|
||||
add_definitions(-DAGW_DNS_SERVER="$ENV{AGW_DNS_SERVER}")
|
||||
add_definitions(-DAGW_DNS_DOMAIN="$ENV{AGW_DNS_DOMAIN}")
|
||||
add_definitions(-DAGW_DNS_PRIMARY="$ENV{AGW_DNS_PRIMARY}")
|
||||
add_definitions(-DAGW_DNS_PORT_UDP="$ENV{AGW_DNS_PORT_UDP}")
|
||||
add_definitions(-DAGW_DNS_PORT_DOT="$ENV{AGW_DNS_PORT_DOT}")
|
||||
add_definitions(-DAGW_DNS_PORT_DOH="$ENV{AGW_DNS_PORT_DOH}")
|
||||
add_definitions(-DAGW_DNS_PORT_DOQ="$ENV{AGW_DNS_PORT_DOQ}")
|
||||
add_definitions(-DAGW_DNS_DOH_PATH="$ENV{AGW_DNS_DOH_PATH}")
|
||||
add_definitions(-DAGW_DNS_RETRY_COUNT="$ENV{AGW_DNS_RETRY_COUNT}")
|
||||
add_definitions(-DAGW_DNS_TIMEOUT_MS="$ENV{AGW_DNS_TIMEOUT_MS}")
|
||||
|
||||
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||
set(PACKAGES ${PACKAGES} Widgets)
|
||||
endif()
|
||||
@@ -227,17 +238,6 @@ if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||
)
|
||||
endif()
|
||||
|
||||
# Copy gateway.json to build directory if exists
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/gateway.json")
|
||||
add_custom_command(
|
||||
TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_CURRENT_LIST_DIR}/gateway.json
|
||||
$<TARGET_FILE_DIR:${PROJECT}>
|
||||
COMMENT "Copying gateway.json to build directory"
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC})
|
||||
qt_finalize_target(${PROJECT})
|
||||
|
||||
|
||||
@@ -6,13 +6,11 @@
|
||||
#include <random>
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QFile>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QMutex>
|
||||
#include <QNetworkReply>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QPromise>
|
||||
#include <QUrl>
|
||||
#include <QHostAddress>
|
||||
@@ -194,39 +192,67 @@ void GatewayController::setTransportsConfig(const TransportsConfig &config)
|
||||
<< "timeout=" << config.timeoutMs;
|
||||
}
|
||||
|
||||
bool GatewayController::loadTransportsConfig(const QString &filePath, const QString &envVarName)
|
||||
TransportsConfig GatewayController::buildTransportsConfig()
|
||||
{
|
||||
// Try environment variable first
|
||||
QString envValue = QProcessEnvironment::systemEnvironment().value(envVarName);
|
||||
if (!envValue.isEmpty()) {
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(envValue.toUtf8(), &parseError);
|
||||
if (parseError.error == QJsonParseError::NoError) {
|
||||
setTransportsConfig(TransportsConfig::fromJson(doc.object()));
|
||||
qDebug() << "[Transport] Loaded config from env:" << envVarName;
|
||||
return true;
|
||||
}
|
||||
qWarning() << "[Transport] Failed to parse env" << envVarName << ":" << parseError.errorString();
|
||||
TransportsConfig config;
|
||||
|
||||
QString server(AGW_DNS_SERVER);
|
||||
QString domain(AGW_DNS_DOMAIN);
|
||||
|
||||
if (server.isEmpty() || domain.isEmpty()) {
|
||||
qDebug() << "[Transport] DNS server/domain not configured, HTTP only";
|
||||
return config;
|
||||
}
|
||||
|
||||
// Try file
|
||||
QFile file(filePath);
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QByteArray data = file.readAll();
|
||||
file.close();
|
||||
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
|
||||
if (parseError.error == QJsonParseError::NoError) {
|
||||
setTransportsConfig(TransportsConfig::fromJson(doc.object()));
|
||||
qDebug() << "[Transport] Loaded config from file:" << filePath;
|
||||
return true;
|
||||
}
|
||||
qWarning() << "[Transport] Failed to parse file" << filePath << ":" << parseError.errorString();
|
||||
|
||||
QString primaryStr = QString(AGW_DNS_PRIMARY).toLower();
|
||||
if (primaryStr == "udp" || primaryStr == "dns_udp") {
|
||||
config.primary = PrimaryTransport::DnsUdp;
|
||||
} else if (primaryStr == "tcp" || primaryStr == "dns_tcp") {
|
||||
config.primary = PrimaryTransport::DnsTcp;
|
||||
} else if (primaryStr == "dot" || primaryStr == "dns_dot") {
|
||||
config.primary = PrimaryTransport::DnsDot;
|
||||
} else if (primaryStr == "doh" || primaryStr == "dns_doh") {
|
||||
config.primary = PrimaryTransport::DnsDoh;
|
||||
} else if (primaryStr == "doq" || primaryStr == "dns_doq") {
|
||||
config.primary = PrimaryTransport::DnsDoq;
|
||||
} else {
|
||||
config.primary = PrimaryTransport::Http;
|
||||
}
|
||||
|
||||
qDebug() << "[Transport] No config found, using defaults";
|
||||
return false;
|
||||
|
||||
int retryCount = QString(AGW_DNS_RETRY_COUNT).toInt();
|
||||
config.retryCount = (retryCount > 0) ? retryCount : 3;
|
||||
|
||||
int timeoutMs = QString(AGW_DNS_TIMEOUT_MS).toInt();
|
||||
config.timeoutMs = (timeoutMs > 0) ? timeoutMs : 10000;
|
||||
|
||||
config.httpEnabled = true;
|
||||
|
||||
auto addTransport = [&](NetworkUtilities::DnsTransport type, const char *portDefine, quint16 defaultPort,
|
||||
const QString &dohPath = QString()) {
|
||||
DnsTransportEntry entry;
|
||||
entry.type = type;
|
||||
entry.server = server;
|
||||
entry.domain = domain;
|
||||
quint16 port = QString(portDefine).toUShort();
|
||||
entry.port = (port > 0) ? port : defaultPort;
|
||||
if (!dohPath.isEmpty()) entry.dohPath = dohPath;
|
||||
config.dnsTransports.append(entry);
|
||||
};
|
||||
|
||||
addTransport(NetworkUtilities::DnsTransport::Udp, AGW_DNS_PORT_UDP, 5353);
|
||||
addTransport(NetworkUtilities::DnsTransport::Tcp, AGW_DNS_PORT_UDP, 5353);
|
||||
addTransport(NetworkUtilities::DnsTransport::Tls, AGW_DNS_PORT_DOT, 853);
|
||||
|
||||
QString dohPath = QString(AGW_DNS_DOH_PATH);
|
||||
if (dohPath.isEmpty()) dohPath = "/dns-query";
|
||||
addTransport(NetworkUtilities::DnsTransport::Https, AGW_DNS_PORT_DOH, 443, dohPath);
|
||||
|
||||
addTransport(NetworkUtilities::DnsTransport::Quic, AGW_DNS_PORT_DOQ, 8853);
|
||||
|
||||
qDebug() << "[Transport] Built config from env: server=" << server << "domain=" << domain
|
||||
<< "transports=" << config.dnsTransports.size() << "primary=" << static_cast<int>(config.primary);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
ErrorCode GatewayController::postParallel(const QString &endpoint, const QJsonObject apiPayload, QByteArray &responseBody)
|
||||
|
||||
@@ -62,8 +62,7 @@ public:
|
||||
// DNS tunneling - send request via DNS transport
|
||||
amnezia::ErrorCode postViaDns(const QString &endpoint, const QJsonObject apiPayload, QByteArray &responseBody);
|
||||
|
||||
// NEW: Load config from file or environment variable
|
||||
bool loadTransportsConfig(const QString &filePath, const QString &envVarName = "AMNEZIA_GATEWAY");
|
||||
static TransportsConfig buildTransportsConfig();
|
||||
void setTransportsConfig(const TransportsConfig &config);
|
||||
|
||||
// NEW: Parallel request via all configured transports (primary first, then others)
|
||||
|
||||
@@ -30,6 +30,17 @@ endif()
|
||||
add_definitions(-DPROD_AGW_PUBLIC_KEY="$ENV{PROD_AGW_PUBLIC_KEY}")
|
||||
add_definitions(-DDEV_AGW_PUBLIC_KEY="$ENV{DEV_AGW_PUBLIC_KEY}")
|
||||
|
||||
add_definitions(-DAGW_DNS_SERVER="$ENV{AGW_DNS_SERVER}")
|
||||
add_definitions(-DAGW_DNS_DOMAIN="$ENV{AGW_DNS_DOMAIN}")
|
||||
add_definitions(-DAGW_DNS_PRIMARY="$ENV{AGW_DNS_PRIMARY}")
|
||||
add_definitions(-DAGW_DNS_PORT_UDP="$ENV{AGW_DNS_PORT_UDP}")
|
||||
add_definitions(-DAGW_DNS_PORT_DOT="$ENV{AGW_DNS_PORT_DOT}")
|
||||
add_definitions(-DAGW_DNS_PORT_DOH="$ENV{AGW_DNS_PORT_DOH}")
|
||||
add_definitions(-DAGW_DNS_PORT_DOQ="$ENV{AGW_DNS_PORT_DOQ}")
|
||||
add_definitions(-DAGW_DNS_DOH_PATH="$ENV{AGW_DNS_DOH_PATH}")
|
||||
add_definitions(-DAGW_DNS_RETRY_COUNT="$ENV{AGW_DNS_RETRY_COUNT}")
|
||||
add_definitions(-DAGW_DNS_TIMEOUT_MS="$ENV{AGW_DNS_TIMEOUT_MS}")
|
||||
|
||||
qt_add_executable(${PROJECT_NAME}
|
||||
tst_transports.cpp
|
||||
${CLIENT_ROOT_DIR}/core/networkUtilities.cpp
|
||||
@@ -65,14 +76,4 @@ if(WIN32)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 crypt32)
|
||||
endif()
|
||||
|
||||
# Copy gateway.json next to the test binary
|
||||
if(EXISTS "${CLIENT_ROOT_DIR}/gateway.json")
|
||||
add_custom_command(
|
||||
TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${CLIENT_ROOT_DIR}/gateway.json"
|
||||
"$<TARGET_FILE_DIR:${PROJECT_NAME}>"
|
||||
)
|
||||
endif()
|
||||
|
||||
add_test(NAME TransportTest COMMAND ${PROJECT_NAME})
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
#include <QDebug>
|
||||
#include <QElapsedTimer>
|
||||
#include <QEventLoop>
|
||||
#include <QFile>
|
||||
#include <QHostAddress>
|
||||
#include <QHostInfo>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
@@ -46,52 +42,44 @@ struct TestConfig {
|
||||
int timeoutMs = 15000;
|
||||
};
|
||||
|
||||
static TestConfig loadConfig(const QString &path)
|
||||
static TestConfig buildConfigFromEnv()
|
||||
{
|
||||
TestConfig cfg;
|
||||
QFile f(path);
|
||||
if (!f.open(QIODevice::ReadOnly)) {
|
||||
qWarning() << "Cannot open config:" << path;
|
||||
return cfg;
|
||||
}
|
||||
QJsonObject json = QJsonDocument::fromJson(f.readAll()).object();
|
||||
|
||||
if (json.contains("http")) {
|
||||
cfg.httpEndpoint = json["http"].toObject().value("endpoint").toString();
|
||||
}
|
||||
cfg.timeoutMs = json.value("timeout_ms").toInt(15000);
|
||||
QString server(AGW_DNS_SERVER);
|
||||
QString domain(AGW_DNS_DOMAIN);
|
||||
|
||||
if (json.contains("dns_transports")) {
|
||||
for (const auto &v : json["dns_transports"].toArray()) {
|
||||
QJsonObject obj = v.toObject();
|
||||
TestConfig::DnsEntry e;
|
||||
e.server = obj.value("server").toString();
|
||||
e.domain = obj.value("domain").toString();
|
||||
e.port = static_cast<quint16>(obj.value("port").toInt(5353));
|
||||
e.dohPath = obj.value("path").toString("/dns-query");
|
||||
cfg.httpEndpoint = QString(DEV_AGW_PUBLIC_KEY).isEmpty()
|
||||
? QString() : QString("http://%1/").arg(server);
|
||||
|
||||
int timeout = QString(AGW_DNS_TIMEOUT_MS).toInt();
|
||||
cfg.timeoutMs = (timeout > 0) ? timeout : 15000;
|
||||
|
||||
if (server.isEmpty() || domain.isEmpty()) return cfg;
|
||||
|
||||
auto addEntry = [&](NetworkUtilities::DnsTransport type, const QString &name,
|
||||
const char *portDefine, quint16 defaultPort, const QString &dohPath = QString()) {
|
||||
TestConfig::DnsEntry e;
|
||||
e.type = type;
|
||||
e.name = name;
|
||||
e.server = server;
|
||||
e.domain = domain;
|
||||
quint16 port = QString(portDefine).toUShort();
|
||||
e.port = (port > 0) ? port : defaultPort;
|
||||
if (!dohPath.isEmpty()) e.dohPath = dohPath;
|
||||
cfg.dnsTransports.append(e);
|
||||
};
|
||||
|
||||
addEntry(NetworkUtilities::DnsTransport::Udp, "UDP", AGW_DNS_PORT_UDP, 5353);
|
||||
addEntry(NetworkUtilities::DnsTransport::Tcp, "TCP", AGW_DNS_PORT_UDP, 5353);
|
||||
addEntry(NetworkUtilities::DnsTransport::Tls, "DoT", AGW_DNS_PORT_DOT, 853);
|
||||
|
||||
QString dohPath = QString(AGW_DNS_DOH_PATH);
|
||||
if (dohPath.isEmpty()) dohPath = "/dns-query";
|
||||
addEntry(NetworkUtilities::DnsTransport::Https, "DoH", AGW_DNS_PORT_DOH, 443, dohPath);
|
||||
|
||||
addEntry(NetworkUtilities::DnsTransport::Quic, "DoQ", AGW_DNS_PORT_DOQ, 8853);
|
||||
|
||||
QString t = obj.value("type").toString().toLower();
|
||||
if (t == "udp") {
|
||||
e.type = NetworkUtilities::DnsTransport::Udp;
|
||||
e.name = "UDP";
|
||||
} else if (t == "tcp") {
|
||||
e.type = NetworkUtilities::DnsTransport::Tcp;
|
||||
e.name = "TCP";
|
||||
} else if (t == "dot" || t == "tls") {
|
||||
e.type = NetworkUtilities::DnsTransport::Tls;
|
||||
e.name = "DoT";
|
||||
} else if (t == "doh" || t == "https") {
|
||||
e.type = NetworkUtilities::DnsTransport::Https;
|
||||
e.name = "DoH";
|
||||
} else if (t == "doq" || t == "quic") {
|
||||
e.type = NetworkUtilities::DnsTransport::Quic;
|
||||
e.name = "DoQ";
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
cfg.dnsTransports.append(e);
|
||||
}
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
@@ -251,15 +239,10 @@ private:
|
||||
private slots:
|
||||
void initTestCase()
|
||||
{
|
||||
QString configPath = QCoreApplication::applicationDirPath() + "/gateway.json";
|
||||
if (!QFile::exists(configPath)) {
|
||||
configPath = QString(CLIENT_SOURCE_DIR) + "/gateway.json";
|
||||
}
|
||||
qDebug() << "Loading config from:" << configPath;
|
||||
m_config = loadConfig(configPath);
|
||||
m_config = buildConfigFromEnv();
|
||||
|
||||
QVERIFY2(!m_config.httpEndpoint.isEmpty(), "gateway.json: http endpoint missing");
|
||||
QVERIFY2(!m_config.dnsTransports.isEmpty(), "gateway.json: no dns_transports configured");
|
||||
QVERIFY2(!m_config.dnsTransports.isEmpty(),
|
||||
"AGW_DNS_SERVER / AGW_DNS_DOMAIN not set — cannot run transport tests");
|
||||
|
||||
qDebug() << "HTTP endpoint:" << m_config.httpEndpoint;
|
||||
qDebug() << "DNS transports:" << m_config.dnsTransports.size();
|
||||
|
||||
@@ -747,8 +747,7 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
|
||||
apiDefs::requestTimeoutMsecs,
|
||||
m_settings->isStrictKillSwitchEnabled());
|
||||
|
||||
// Load transports config from file or env
|
||||
gatewayController.loadTransportsConfig("gateway.json", "AMNEZIA_GATEWAY");
|
||||
gatewayController.setTransportsConfig(GatewayController::buildTransportsConfig());
|
||||
|
||||
ErrorCode errorCode = gatewayController.postParallel(endpoint, apiPayload, responseBody);
|
||||
|
||||
@@ -962,9 +961,7 @@ ErrorCode ApiConfigsController::executeRequest(const QString &endpoint, const QJ
|
||||
apiDefs::requestTimeoutMsecs,
|
||||
m_settings->isStrictKillSwitchEnabled());
|
||||
|
||||
// Load transports config from file or env
|
||||
gatewayController.loadTransportsConfig("gateway.json", "AMNEZIA_GATEWAY");
|
||||
gatewayController.setTransportsConfig(GatewayController::buildTransportsConfig());
|
||||
|
||||
// Parallel request via all configured transports (HTTP + DNS)
|
||||
return gatewayController.postParallel(endpoint, apiPayload, responseBody);
|
||||
}
|
||||
|
||||
@@ -52,8 +52,7 @@ void ApiNewsController::fetchNews(bool showError)
|
||||
apiDefs::requestTimeoutMsecs,
|
||||
m_settings->isStrictKillSwitchEnabled());
|
||||
|
||||
// Load transports config from file or env
|
||||
gatewayController.loadTransportsConfig("gateway.json", "AMNEZIA_GATEWAY");
|
||||
gatewayController.setTransportsConfig(GatewayController::buildTransportsConfig());
|
||||
|
||||
QByteArray responseBody;
|
||||
ErrorCode errorCode = gatewayController.postParallel(endpoint, payload, responseBody);
|
||||
|
||||
@@ -77,8 +77,7 @@ bool ApiSettingsController::getAccountInfo(bool reload)
|
||||
requestTimeoutMsecs,
|
||||
m_settings->isStrictKillSwitchEnabled());
|
||||
|
||||
// Load transports config from file or env
|
||||
gatewayController.loadTransportsConfig("gateway.json", "AMNEZIA_GATEWAY");
|
||||
gatewayController.setTransportsConfig(GatewayController::buildTransportsConfig());
|
||||
|
||||
ErrorCode errorCode = gatewayController.postParallel(endpoint, apiPayload, responseBody);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user