diff --git a/makespec/BUILDVERSION b/makespec/BUILDVERSION index b9e946f9..f3eb4e87 100644 --- a/makespec/BUILDVERSION +++ b/makespec/BUILDVERSION @@ -1 +1 @@ -5675 +5676 diff --git a/src/base/models/CoreObjectModels.hpp b/src/base/models/CoreObjectModels.hpp index bf7f5b78..90d75284 100644 --- a/src/base/models/CoreObjectModels.hpp +++ b/src/base/models/CoreObjectModels.hpp @@ -265,7 +265,7 @@ namespace Qv2ray::base::objects QList alpn; QList certificates; bool disableSystemRoot; - TLSObject() : serverName(), allowInsecure(), allowInsecureCiphers(), disableSessionResumption(), certificates(), disableSystemRoot(){}; + TLSObject() : serverName(), allowInsecure(), allowInsecureCiphers(), disableSessionResumption(true), certificates(), disableSystemRoot(){}; JSONSTRUCT_REGISTER(TLSObject, F(serverName, allowInsecure, allowInsecureCiphers, disableSessionResumption, alpn, certificates, disableSystemRoot)) }; } // namespace transfer diff --git a/src/base/models/QvSettingsObject.hpp b/src/base/models/QvSettingsObject.hpp index 2d4aad45..4ebbe421 100644 --- a/src/base/models/QvSettingsObject.hpp +++ b/src/base/models/QvSettingsObject.hpp @@ -94,9 +94,9 @@ namespace Qv2ray::base::config struct Qv2rayConfig_Advanced { bool setAllowInsecure; - bool setAllowInsecureCiphers; + bool setSessionResumption; bool testLatencyPeriodcally; - JSONSTRUCT_REGISTER(Qv2rayConfig_Advanced, F(setAllowInsecure, setAllowInsecureCiphers, testLatencyPeriodcally)) + JSONSTRUCT_REGISTER(Qv2rayConfig_Advanced, F(setAllowInsecure, setSessionResumption, testLatencyPeriodcally)) }; enum Qv2rayLatencyTestingMethod diff --git a/src/core/connection/Serialization.cpp b/src/core/connection/Serialization.cpp index d601eb70..78797901 100644 --- a/src/core/connection/Serialization.cpp +++ b/src/core/connection/Serialization.cpp @@ -16,11 +16,11 @@ namespace Qv2ray::core::connection QList> connectionConf; const auto mkAllowInsecure = [](QJsonObject &conf) { auto allowI = GlobalConfig.advancedConfig.setAllowInsecure; - auto allowIC = GlobalConfig.advancedConfig.setAllowInsecureCiphers; - if (allowI || allowIC) + auto allowSR = GlobalConfig.advancedConfig.setSessionResumption; + if (allowI || allowSR) { QJsonIO::SetValue(conf, allowI, "outbounds", 0, "streamSettings", "tlsSettings", "allowInsecure"); - QJsonIO::SetValue(conf, allowIC, "outbounds", 0, "streamSettings", "tlsSettings", "allowInsecureCiphers"); + QJsonIO::SetValue(conf, !allowSR, "outbounds", 0, "streamSettings", "tlsSettings", "disableSessionResumption"); } }; if (link.startsWith("vmess://") && link.contains("@")) diff --git a/src/core/handler/KernelInstanceHandler.cpp b/src/core/handler/KernelInstanceHandler.cpp index 74329195..c3870ae9 100644 --- a/src/core/handler/KernelInstanceHandler.cpp +++ b/src/core/handler/KernelInstanceHandler.cpp @@ -36,31 +36,51 @@ namespace Qv2ray::core::handler StopConnection(); } - std::optional KernelInstanceHandler::StartConnection(const ConnectionGroupPair &id, CONFIGROOT fullConfig) + std::optional KernelInstanceHandler::CheckPort(QMap hosts, QMap ports, int plugins) { - StopConnection(); - inboundPorts = GetConfigInboundPorts(fullConfig); - inboundHosts = GetConfigInboundHosts(fullConfig); // // Check inbound port allocation issue. QStringList portDetectionErrorMessage; auto portDetectionMsg = tr("Another process is using the port required to start the connection:") + NEWLINE + NEWLINE; - for (const auto &key : inboundPorts.keys()) + for (const auto &key : ports.keys()) { - auto result = components::port::CheckTCPPortStatus(inboundHosts[key], inboundPorts[key]); + auto result = components::port::CheckTCPPortStatus(hosts[key], ports[key]); if (!result) { portDetectionErrorMessage << tr("Port: %1 for listening IP: %2 for inbound tag: \"%3\"") // - .arg(inboundPorts[key]) - .arg(inboundHosts[key]) + .arg(ports[key]) + .arg(hosts[key]) .arg(key); } } + if (GlobalConfig.pluginConfig.v2rayIntegration) + { + for (int i = 0; i <= plugins; i++) + { + auto result = components::port::CheckTCPPortStatus("127.0.0.1", GlobalConfig.pluginConfig.portAllocationStart + i); + if (!result) + { + portDetectionErrorMessage << tr("Port: %1 for listening IP: 127.0.0.1 for plugin integration.") + .arg(GlobalConfig.pluginConfig.portAllocationStart + i); + } + } + } if (!portDetectionErrorMessage.isEmpty()) { portDetectionMsg += portDetectionErrorMessage.join(NEWLINE); return portDetectionMsg; } + else + { + return std::nullopt; + } + } + + std::optional KernelInstanceHandler::StartConnection(const ConnectionGroupPair &id, CONFIGROOT fullConfig) + { + StopConnection(); + inboundPorts = GetConfigInboundPorts(fullConfig); + inboundHosts = GetConfigInboundHosts(fullConfig); // PluginHost->Send_ConnectivityEvent({ GetDisplayName(id.connectionId), inboundPorts, Events::Connectivity::Connecting }); QList> inboundInfo; @@ -70,7 +90,7 @@ namespace Qv2ray::core::handler inboundInfo.push_back({ inbound["protocol"].toString(), inbound["port"].toInt(), inbound["tag"].toString() }); } // - using k = Qv2rayPlugin::QvPluginKernel; + using _k_ = Qv2rayPlugin::QvPluginKernel; if (GlobalConfig.pluginConfig.v2rayIntegration) { // @@ -105,104 +125,112 @@ namespace Qv2ray::core::handler // QMap _inboundSettings; - _inboundSettings[k::KERNEL_HTTP_ENABLED] = false; - _inboundSettings[k::KERNEL_SOCKS_ENABLED] = true; - _inboundSettings.insert(k::KERNEL_SOCKS_PORT, pluginPort); + _inboundSettings[_k_::KERNEL_HTTP_ENABLED] = false; + _inboundSettings[_k_::KERNEL_SOCKS_ENABLED] = true; + _inboundSettings.insert(_k_::KERNEL_SOCKS_PORT, pluginPort); LOG(MODULE_VCORE, "V2rayIntegration: " + QSTRN(pluginPort) + "=" + outProtocol) - + // const auto pluginOutSettings = GenerateHTTPSOCKSOut("127.0.0.1", pluginPort, false, "", ""); const auto pluginOut = GenerateOutboundEntry("socks", pluginOutSettings, {}, {}, "0.0.0.0", outbound["tag"].toString()); // // Add the integration outbound to the list. processedOutbounds.push_back(pluginOut); - pluginPort++; - - _inboundSettings[k::KERNEL_SOCKS_UDP_ENABLED] = GlobalConfig.inboundConfig.socksSettings.enableUDP; - _inboundSettings[k::KERNEL_SOCKS_LOCAL_ADDRESS] = GlobalConfig.inboundConfig.socksSettings.localIP; - _inboundSettings[k::KERNEL_LISTEN_ADDRESS] = "127.0.0.1"; + // + _inboundSettings[_k_::KERNEL_SOCKS_UDP_ENABLED] = GlobalConfig.inboundConfig.socksSettings.enableUDP; + _inboundSettings[_k_::KERNEL_SOCKS_LOCAL_ADDRESS] = GlobalConfig.inboundConfig.socksSettings.localIP; + _inboundSettings[_k_::KERNEL_LISTEN_ADDRESS] = "127.0.0.1"; LOG(MODULE_CONNECTION, "Sending connection settings to kernel.") activeKernels[outProtocol]->SetConnectionSettings(_inboundSettings, outbound["settings"].toObject()); } LOG(MODULE_CONNECTION, "Applying new outbound settings.") fullConfig["outbounds"] = processedOutbounds; } - // - // Process routing entries - // - // No needs to process routing entries since each plugin is map to an unique outbound with the same tag. - // - // ================================================================================================ - // - bool hasAllKernelStarted = true; - for (auto &[kernel, kernelObject] : activeKernels) + RemoveEmptyMuxFilter(fullConfig); + } + // + // ======================================================================= Start Kernels + // + { + const auto portResult = CheckPort(inboundHosts, inboundPorts, activeKernels.size()); + if (portResult) { - LOG(MODULE_CONNECTION, "Starting kernel: " + kernel) - bool status = kernelObject->StartKernel(); - connect(kernelObject.get(), &QvPluginKernel::OnKernelCrashed, this, &KernelInstanceHandler::OnKernelCrashed_p); - connect(kernelObject.get(), &QvPluginKernel::OnKernelLogAvailable, this, &KernelInstanceHandler::OnKernelLog_p); - hasAllKernelStarted = hasAllKernelStarted && status; - if (!status) + LOG(MODULE_CONNECTION, ACCESS_OPTIONAL_VALUE(portResult)) + return portResult; + } + auto firstOutbound = fullConfig["outbounds"].toArray().first().toObject(); + const auto firstOutboundProtocol = firstOutbound["protocol"].toString(); + if (GlobalConfig.pluginConfig.v2rayIntegration) + { + LOG(MODULE_VCORE, "Starting kernels with V2rayIntegration.") + bool hasAllKernelStarted = true; + for (auto &[kernel, kernelObject] : activeKernels) { - LOG(MODULE_CONNECTION, "Plugin Kernel: " + kernel + " failed to start.") - break; + LOG(MODULE_CONNECTION, "Starting kernel: " + kernel) + bool status = kernelObject->StartKernel(); + connect(kernelObject.get(), &QvPluginKernel::OnKernelCrashed, this, &KernelInstanceHandler::OnKernelCrashed_p); + connect(kernelObject.get(), &QvPluginKernel::OnKernelLogAvailable, this, &KernelInstanceHandler::OnKernelLog_p); + hasAllKernelStarted = hasAllKernelStarted && status; + if (!status) + { + LOG(MODULE_CONNECTION, "Plugin Kernel: " + kernel + " failed to start.") + break; + } + } + if (!hasAllKernelStarted) + { + StopConnection(); + return tr("A plugin kernel failed to start. Please check the outbound settings."); + } + currentId = id; + // + // Also start V2ray-core. + auto result = vCoreInstance->StartConnection(fullConfig); + // + if (result.has_value()) + { + StopConnection(); + PluginHost->Send_ConnectivityEvent({ GetDisplayName(id.connectionId), inboundPorts, Events::Connectivity::Disconnected }); + return result; + } + else + { + emit OnConnected(id); + PluginHost->Send_ConnectivityEvent({ GetDisplayName(id.connectionId), inboundPorts, Events::Connectivity::Connected }); } } - if (!hasAllKernelStarted) + else if (outboundKernelMap.contains(firstOutboundProtocol)) { - StopConnection(); - return tr("A plugin kernel failed to start. Please check the outbound settings."); - } - currentId = id; - // - // Also start V2ray-core. - auto result = vCoreInstance->StartConnection(fullConfig); - // - if (result.has_value()) - { - StopConnection(); - PluginHost->Send_ConnectivityEvent({ GetDisplayName(id.connectionId), inboundPorts, Events::Connectivity::Disconnected }); - return result; - } - else - { - emit OnConnected(id); - PluginHost->Send_ConnectivityEvent({ GetDisplayName(id.connectionId), inboundPorts, Events::Connectivity::Connected }); - } - } - else - { - LOG(MODULE_CONNECTION, "Starting kernel without V2ray Integration") - auto firstOutbound = fullConfig["outbounds"].toArray().first().toObject(); - const auto protocol = firstOutbound["protocol"].toString(); - if (outboundKernelMap.contains(protocol)) - { - LOG(MODULE_CONNECTION, "Found existing kernel for: " + protocol) + LOG(MODULE_CONNECTION, "Starting kernel " + firstOutboundProtocol + " without V2ray Integration") { auto kernel = PluginHost->CreatePluginKernel(outboundKernelMap[firstOutbound["protocol"].toString()]); - activeKernels[protocol] = std::move(kernel); + activeKernels[firstOutboundProtocol] = std::move(kernel); } +#define kernel (activeKernels[firstOutboundProtocol].get()) + connect(kernel, &QvPluginKernel::OnKernelStatsAvailable, this, &KernelInstanceHandler::OnStatsDataRcvd_p); + connect(kernel, &QvPluginKernel::OnKernelCrashed, this, &KernelInstanceHandler::OnKernelCrashed_p); + connect(kernel, &QvPluginKernel::OnKernelLogAvailable, this, &KernelInstanceHandler::OnKernelLog_p); +#undef kernel + currentId = id; + // QMap pluginInboundPort; + for (const auto &[_protocol, _port, _tag] : inboundInfo) { if (_protocol != "http" && _protocol != "socks") continue; - pluginInboundPort[k::KERNEL_HTTP_ENABLED] = pluginInboundPort[k::KERNEL_HTTP_ENABLED].toBool() || _protocol == "http"; - pluginInboundPort[k::KERNEL_SOCKS_ENABLED] = pluginInboundPort[k::KERNEL_SOCKS_ENABLED].toBool() || _protocol == "socks"; - pluginInboundPort.insert(_protocol.toLower() == "http" ? k::KERNEL_HTTP_PORT : k::KERNEL_SOCKS_PORT, _port); + pluginInboundPort[_k_::KERNEL_HTTP_ENABLED] = pluginInboundPort[_k_::KERNEL_HTTP_ENABLED].toBool() || _protocol == "http"; + pluginInboundPort[_k_::KERNEL_SOCKS_ENABLED] = pluginInboundPort[_k_::KERNEL_SOCKS_ENABLED].toBool() || _protocol == "socks"; + pluginInboundPort.insert(_protocol.toLower() == "http" ? _k_::KERNEL_HTTP_PORT : _k_::KERNEL_SOCKS_PORT, _port); } - connect(activeKernels[protocol].get(), &QvPluginKernel::OnKernelStatsAvailable, this, &KernelInstanceHandler::OnStatsDataRcvd_p); - connect(activeKernels[protocol].get(), &QvPluginKernel::OnKernelCrashed, this, &KernelInstanceHandler::OnKernelCrashed_p); - connect(activeKernels[protocol].get(), &QvPluginKernel::OnKernelLogAvailable, this, &KernelInstanceHandler::OnKernelLog_p); - currentId = id; - // - pluginInboundPort[k::KERNEL_SOCKS_UDP_ENABLED] = GlobalConfig.inboundConfig.socksSettings.enableUDP; - pluginInboundPort[k::KERNEL_SOCKS_LOCAL_ADDRESS] = GlobalConfig.inboundConfig.socksSettings.localIP; - pluginInboundPort[k::KERNEL_LISTEN_ADDRESS] = GlobalConfig.inboundConfig.listenip; - // - activeKernels[protocol]->SetConnectionSettings(pluginInboundPort, firstOutbound["settings"].toObject()); - bool kernelStarted = activeKernels[protocol]->StartKernel(); + pluginInboundPort[_k_::KERNEL_SOCKS_UDP_ENABLED] = GlobalConfig.inboundConfig.socksSettings.enableUDP; + pluginInboundPort[_k_::KERNEL_SOCKS_LOCAL_ADDRESS] = GlobalConfig.inboundConfig.socksSettings.localIP; + pluginInboundPort[_k_::KERNEL_LISTEN_ADDRESS] = GlobalConfig.inboundConfig.listenip; + // + activeKernels[firstOutboundProtocol]->SetConnectionSettings(pluginInboundPort, firstOutbound["settings"].toObject()); + + bool kernelStarted = activeKernels[firstOutboundProtocol]->StartKernel(); if (kernelStarted) { emit OnConnected(id); @@ -216,7 +244,7 @@ namespace Qv2ray::core::handler } else { - LOG(MODULE_CONNECTION, "Starting V2ray without kernel") + LOG(MODULE_CONNECTION, "Starting V2ray without plugin.") currentId = id; auto result = vCoreInstance->StartConnection(fullConfig); if (result.has_value()) diff --git a/src/core/handler/KernelInstanceHandler.hpp b/src/core/handler/KernelInstanceHandler.hpp index 748d9146..8af88521 100644 --- a/src/core/handler/KernelInstanceHandler.hpp +++ b/src/core/handler/KernelInstanceHandler.hpp @@ -20,6 +20,10 @@ namespace Qv2ray::core::handler { return currentId; } + int ActivePluginKernelsCount() const + { + return activeKernels.size(); + } const QMap InboundPorts() const { return inboundPorts; @@ -41,6 +45,9 @@ namespace Qv2ray::core::handler void OnKernelLog_p(const QString &log); void OnStatsDataRcvd_p(const quint64 uploadSpeed, const quint64 downloadSpeed); + private: + static std::optional CheckPort(QMap hosts, QMap ports, int plugins); + private: QMap outboundKernelMap; // Since QMap does not support std::unique_ptr, we use std::map<> diff --git a/src/ui/windows/w_PreferencesWindow.cpp b/src/ui/windows/w_PreferencesWindow.cpp index 7209f048..3beb1f83 100644 --- a/src/ui/windows/w_PreferencesWindow.cpp +++ b/src/ui/windows/w_PreferencesWindow.cpp @@ -143,6 +143,7 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QvDialog(parent), Curren // pluginKernelV2rayIntegrationCB->setChecked(CurrentConfig.pluginConfig.v2rayIntegration); pluginKernelPortAllocateCB->setValue(CurrentConfig.pluginConfig.portAllocationStart); + pluginKernelPortAllocateCB->setEnabled(CurrentConfig.pluginConfig.v2rayIntegration); // // latencyTCPingRB->setChecked(CurrentConfig.networkConfig.latencyTestingMethod == TCPING); @@ -163,7 +164,7 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QvDialog(parent), Curren // // Advanced config. setAllowInsecureCB->setChecked(CurrentConfig.advancedConfig.setAllowInsecure); - setAllowInsecureCiphersCB->setChecked(CurrentConfig.advancedConfig.setAllowInsecureCiphers); + setSessionResumptionCB->setChecked(CurrentConfig.advancedConfig.setSessionResumption); setTestLatenctCB->setChecked(CurrentConfig.advancedConfig.testLatencyPeriodcally); // dnsSettingsWidget = new DnsSettingsWidget(this); @@ -854,12 +855,17 @@ void PreferencesWindow::on_updateChannelCombo_currentIndexChanged(int index) void PreferencesWindow::on_pluginKernelV2rayIntegrationCB_stateChanged(int arg1) { LOADINGCHECK + if (KernelInstance->ActivePluginKernelsCount() > 0) + NEEDRESTART; CurrentConfig.pluginConfig.v2rayIntegration = arg1 == Qt::Checked; + pluginKernelPortAllocateCB->setEnabled(arg1 == Qt::Checked); } void PreferencesWindow::on_pluginKernelPortAllocateCB_valueChanged(int arg1) { LOADINGCHECK + if (KernelInstance->ActivePluginKernelsCount() > 0) + NEEDRESTART; CurrentConfig.pluginConfig.portAllocationStart = arg1; } @@ -901,14 +907,14 @@ void PreferencesWindow::on_setTestLatenctCB_stateChanged(int arg1) CurrentConfig.advancedConfig.testLatencyPeriodcally = arg1 == Qt::Checked; } -void PreferencesWindow::on_setAllowInsecureCiphersCB_stateChanged(int arg1) +void PreferencesWindow::on_setSessionResumptionCB_stateChanged(int arg1) { LOADINGCHECK if (arg1 == Qt::Checked) { - QvMessageBoxWarn(this, tr("Dangerous Operation"), tr("You will lose the advantage of TLS and make your connection under MITM attack.")); + QvMessageBoxWarn(this, tr("Dangerous Operation"), tr("This will make your TLS fingerpring different from common golang programs.")); } - CurrentConfig.advancedConfig.setAllowInsecureCiphers = arg1 == Qt::Checked; + CurrentConfig.advancedConfig.setSessionResumption = arg1 == Qt::Checked; } void PreferencesWindow::on_quietModeCB_stateChanged(int arg1) diff --git a/src/ui/windows/w_PreferencesWindow.hpp b/src/ui/windows/w_PreferencesWindow.hpp index 76d16884..e6eea400 100644 --- a/src/ui/windows/w_PreferencesWindow.hpp +++ b/src/ui/windows/w_PreferencesWindow.hpp @@ -97,7 +97,7 @@ class PreferencesWindow void on_qvProxyPortCB_valueChanged(int arg1); void on_setAllowInsecureCB_stateChanged(int arg1); void on_setTestLatenctCB_stateChanged(int arg1); - void on_setAllowInsecureCiphersCB_stateChanged(int arg1); + void on_setSessionResumptionCB_stateChanged(int arg1); void on_quietModeCB_stateChanged(int arg1); void on_tproxGroupBox_toggled(bool arg1); void on_tProxyPort_valueChanged(int arg1); diff --git a/src/ui/windows/w_PreferencesWindow.ui b/src/ui/windows/w_PreferencesWindow.ui index a84dbb74..d68ba2ec 100644 --- a/src/ui/windows/w_PreferencesWindow.ui +++ b/src/ui/windows/w_PreferencesWindow.ui @@ -608,7 +608,7 @@ But could damage your server if improperly used. - Set AllowInsecureCiphers By Default + Enable SessionResumption By Default Qt::PlainText @@ -616,7 +616,7 @@ But could damage your server if improperly used. - + Enabled diff --git a/translations/en_US.ts b/translations/en_US.ts index 133bd423..d1ce2012 100644 --- a/translations/en_US.ts +++ b/translations/en_US.ts @@ -1341,7 +1341,7 @@ But could dramatically damage your server if improperly used. - Set AllowInsecureCiphers By Default + Enable SessionResumption By Default @@ -1765,6 +1765,10 @@ Custom DNS Settings You will lose the advantage of TLS and make your connection under MITM attack. + + This will make your TLS fingerpring different from common golang programs. + + This will (probably) make it easy to fingerprint your connection. diff --git a/translations/ja_JP.ts b/translations/ja_JP.ts index f49c36ba..685d61ca 100644 --- a/translations/ja_JP.ts +++ b/translations/ja_JP.ts @@ -1462,6 +1462,10 @@ You will lose the advantage of TLS and make your connection under MITM attack. TLSの保護を失い、MITMの攻撃を受ける可能性が高くなります。 + + This will make your TLS fingerpring different from common golang programs. + + This will (probably) make it easy to fingerprint your connection. そのため、(おそらく)あなたの接続が特定しやすくなります。 @@ -1789,8 +1793,8 @@ But could dramatically damage your server if improperly used. しかし、不適切な使用の場合、不都合が生じる可能性があります。 - Set AllowInsecureCiphers By Default - デフォルトで AllowInsecureCiphers を設定する + Enable SessionResumption By Default + デフォルトで SessionResumption を有効にする IPv4 address, e.g. '127.0.0.1' diff --git a/translations/ru_RU.ts b/translations/ru_RU.ts index 98e31ad2..4ab14eef 100644 --- a/translations/ru_RU.ts +++ b/translations/ru_RU.ts @@ -1458,6 +1458,10 @@ You will lose the advantage of TLS and make your connection under MITM attack. + + This will make your TLS fingerpring different from common golang programs. + + This will (probably) make it easy to fingerprint your connection. @@ -1780,7 +1784,7 @@ But could dramatically damage your server if improperly used. - Set AllowInsecureCiphers By Default + Enable SessionResumption By Default diff --git a/translations/zh_CN.ts b/translations/zh_CN.ts index e8edcc7f..1e62a8ce 100644 --- a/translations/zh_CN.ts +++ b/translations/zh_CN.ts @@ -1442,6 +1442,10 @@ You will lose the advantage of TLS and make your connection under MITM attack. 你会失去 TLS 的保护,并可能使您的连接受害于中间人攻击(MitM)。 + + 这将使你的 TLS 指纹与常见的 golang 程序不同。 + + This will (probably) make it easy to fingerprint your connection. 这将让 GFW 更容易识别出您的连接。 @@ -1789,8 +1793,8 @@ But could dramatically damage your server if improperly used. 但若使用不当,可能会造成负面影响。 - Set AllowInsecureCiphers By Default - 默认设置 AllowInsecureCiphers + Enable SessionResumption By Default + 默认允许 SessionResumption IPv4 address, e.g. '127.0.0.1'